]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/karo/common/mmc.c
karo: merge with Ka-Ro specific tree for secure boot support
[karo-tx-uboot.git] / board / karo / common / mmc.c
1 /*
2  * (C) Copyright 2014 Lothar Waßmann <LW@KARO-electronics.de>
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <common.h>
19 #include <errno.h>
20 #include <libfdt.h>
21 #include <fdt_support.h>
22 #include <mmc.h>
23 #include <mxcfb.h>
24 #include <fs.h>
25 #include <fat.h>
26 #include <malloc.h>
27 #include <linux/list.h>
28 #include <linux/fb.h>
29 #include <jffs2/load_kernel.h>
30
31 #include "karo.h"
32
33 DECLARE_GLOBAL_DATA_PTR;
34
35 #define MAX_SEARCH_PARTITIONS 16
36
37 static int find_partitions(const char *ifname, int devno, int fstype,
38                         block_dev_desc_t **dev_desc, disk_partition_t *info)
39 {
40         int ret = -1;
41         char *dup_str = NULL;
42         int p;
43         int part;
44         block_dev_desc_t *dd;
45
46         dd = get_dev(ifname, devno);
47         if (!dd || dd->type == DEV_TYPE_UNKNOWN) {
48                 printf("** Bad device %s %d **\n", ifname, devno);
49                 return -1;
50         }
51         init_part(dd);
52
53         /*
54          * No partition table on device,
55          * or user requested partition 0 (entire device).
56          */
57         if (dd->part_type == PART_TYPE_UNKNOWN) {
58                 printf("** No partition table on device %s %d **\n",
59                         ifname, devno);
60                 goto cleanup;
61         }
62
63         part = 0;
64         for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
65                 ret = get_partition_info(dd, p, info);
66                 if (ret)
67                         continue;
68
69                 if (fat_register_device(dd, p) == 0) {
70                         part = p;
71                         dd->log2blksz = LOG2(dd->blksz);
72                         break;
73                 }
74         }
75         if (!part) {
76                 printf("** No valid partition on device %s %d **\n",
77                         ifname, devno);
78                 ret = -1;
79                 goto cleanup;
80         }
81
82         ret = part;
83         *dev_desc = dd;
84
85 cleanup:
86         free(dup_str);
87         return ret;
88 }
89
90 static int karo_mmc_find_part(struct mmc *mmc, const char *part, int devno,
91                         disk_partition_t *part_info)
92 {
93         int ret;
94         block_dev_desc_t *mmc_dev;
95
96 #if defined(CONFIG_SYS_DTB_OFFSET) && defined(CONFIG_SYS_MMC_ENV_PART)
97         if (strcmp(part, "dtb") == 0) {
98                 const int partnum = CONFIG_SYS_MMC_ENV_PART;
99
100                 part_info->blksz = mmc->read_bl_len;
101                 part_info->start = CONFIG_SYS_DTB_OFFSET / part_info->blksz;
102                 part_info->size = CONFIG_SYS_DTB_PART_SIZE / part_info->blksz;
103                 printf("Using virtual partition %s(%d) ["LBAF".."LBAF"]\n",
104                         part, partnum, part_info->start,
105                         part_info->start + part_info->size - 1);
106                 return partnum;
107         }
108 #endif
109         ret = find_partitions("mmc", devno, FS_TYPE_FAT, &mmc_dev, part_info);
110         if (ret < 0) {
111                 printf("No (e)MMC partition found: %d\n", ret);
112                 return ret;
113         }
114         return 0;
115 }
116
117 int karo_load_mmc_part(const char *part, void *addr, size_t len)
118 {
119         int ret;
120         struct mmc *mmc;
121         disk_partition_t part_info;
122         int devno = CONFIG_SYS_MMC_ENV_DEV;
123         lbaint_t blk_cnt;
124         int partnum;
125
126         mmc = find_mmc_device(devno);
127         if (!mmc) {
128                 printf("Failed to find mmc%u\n", devno);
129                 return -ENODEV;
130         }
131
132         if (mmc_init(mmc)) {
133                 printf("Failed to init MMC device %d\n", devno);
134                 return -EIO;
135         }
136
137         blk_cnt = DIV_ROUND_UP(len, mmc->read_bl_len);
138
139         partnum = karo_mmc_find_part(mmc, part, devno, &part_info);
140         if (partnum > 0) {
141                 if (part_info.start + blk_cnt < part_info.start) {
142                         printf("%s: given length 0x%08x exceeds size of partition\n",
143                                 __func__, len);
144                         return -EINVAL;
145                 }
146                 if (part_info.start + blk_cnt > mmc->block_dev.lba)
147                         blk_cnt = mmc->block_dev.lba - part_info.start;
148
149                 mmc_switch_part(devno, partnum);
150
151                 memset(addr, 0xee, len);
152
153                 debug("Reading 0x"LBAF" blks from MMC partition %d offset 0x"LBAF" to %p\n",
154                         blk_cnt, partnum, part_info.start, addr);
155                 ret = mmc->block_dev.block_read(devno, part_info.start, blk_cnt, addr);
156                 if (ret == 0) {
157                         printf("Failed to read MMC partition %s\n", part);
158                         ret = -EIO;
159                         goto out;
160                 }
161                 debug("Read %u (%u) byte from partition '%s' @ offset 0x"LBAF"\n",
162                         ret * mmc->read_bl_len, len, part, part_info.start);
163         } else if (partnum == 0) {
164                 loff_t len_read;
165
166                 debug("Reading file %s from mmc partition %d\n", part,
167                         partnum);
168                 ret = fs_read(part, (ulong)addr, 0, len, &len_read);
169                 if (ret < 0) {
170                         printf("Failed to read %u byte from mmc partition %d\n",
171                                 len, partnum);
172                         goto out;
173                 }
174                 if (len_read < len) {
175                         printf("Read only %llu of %u bytes\n", (u64)len_read, len);
176                 }
177         } else {
178                 ret = partnum;
179                 goto out;
180         }
181         ret = 0;
182 out:
183         if (partnum > 0)
184                 mmc_switch_part(devno, 0);
185         return ret < 0 ? ret : 0;
186 }