Commit 638b3e8342e4b395f9e961bfac200420f29874a3
Exists in
v2017.01-smarct4x
and in
40 other branches
Merge branch 'master' of git://git.denx.de/u-boot-mmc
Showing 19 changed files Side-by-side Diff
- README
- board/BuR/common/common.c
- common/cmd_fuse.c
- common/cmd_mmc.c
- common/cmd_nand.c
- common/cmd_otp.c
- common/cmd_part.c
- common/console.c
- disk/part.c
- drivers/mmc/Makefile
- drivers/mmc/fsl_esdhc.c
- drivers/mmc/mmc.c
- drivers/mmc/rpmb.c
- include/common.h
- include/configs/kwb.h
- include/configs/tseries.h
- include/mmc.h
- include/part.h
- lib/Makefile
README
... | ... | @@ -1534,6 +1534,16 @@ |
1534 | 1534 | CONFIG_SH_MMCIF_CLK |
1535 | 1535 | Define the clock frequency for MMCIF |
1536 | 1536 | |
1537 | + CONFIG_GENERIC_MMC | |
1538 | + Enable the generic MMC driver | |
1539 | + | |
1540 | + CONFIG_SUPPORT_EMMC_BOOT | |
1541 | + Enable some additional features of the eMMC boot partitions. | |
1542 | + | |
1543 | + CONFIG_SUPPORT_EMMC_RPMB | |
1544 | + Enable the commands for reading, writing and programming the | |
1545 | + key for the Replay Protection Memory Block partition in eMMC. | |
1546 | + | |
1537 | 1547 | - USB Device Firmware Update (DFU) class support: |
1538 | 1548 | CONFIG_DFU_FUNCTION |
1539 | 1549 | This enables the USB portion of the DFU USB class |
board/BuR/common/common.c
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | #include <asm/arch/clock.h> |
20 | 20 | #include <asm/arch/gpio.h> |
21 | 21 | #include <asm/arch/sys_proto.h> |
22 | +#include <asm/arch/mmc_host_def.h> | |
22 | 23 | #include <asm/io.h> |
23 | 24 | #include <asm/gpio.h> |
24 | 25 | #include <i2c.h> |
... | ... | @@ -214,4 +215,10 @@ |
214 | 215 | return rv; |
215 | 216 | } |
216 | 217 | #endif /* CONFIG_DRIVER_TI_CPSW */ |
218 | +#if defined(CONFIG_GENERIC_MMC) && !defined(CONFIG_SPL_BUILD) | |
219 | +int board_mmc_init(bd_t *bis) | |
220 | +{ | |
221 | + return omap_mmc_init(1, 0, 0, -1, -1); | |
222 | +} | |
223 | +#endif |
common/cmd_fuse.c
... | ... | @@ -33,15 +33,8 @@ |
33 | 33 | "what you are doing!\n" |
34 | 34 | "\nReally perform this fuse programming? <y/N>\n"); |
35 | 35 | |
36 | - if (getc() == 'y') { | |
37 | - int c; | |
38 | - | |
39 | - putc('y'); | |
40 | - c = getc(); | |
41 | - putc('\n'); | |
42 | - if (c == '\r') | |
43 | - return 1; | |
44 | - } | |
36 | + if (confirm_yesno()) | |
37 | + return 1; | |
45 | 38 | |
46 | 39 | puts("Fuse programming aborted\n"); |
47 | 40 | return 0; |
common/cmd_mmc.c
... | ... | @@ -71,12 +71,6 @@ |
71 | 71 | ); |
72 | 72 | #else /* !CONFIG_GENERIC_MMC */ |
73 | 73 | |
74 | -enum mmc_state { | |
75 | - MMC_INVALID, | |
76 | - MMC_READ, | |
77 | - MMC_WRITE, | |
78 | - MMC_ERASE, | |
79 | -}; | |
80 | 74 | static void print_mmcinfo(struct mmc *mmc) |
81 | 75 | { |
82 | 76 | printf("Device: %s\n", mmc->cfg->name); |
... | ... | @@ -98,7 +92,18 @@ |
98 | 92 | |
99 | 93 | printf("Bus Width: %d-bit\n", mmc->bus_width); |
100 | 94 | } |
101 | - | |
95 | +static struct mmc *init_mmc_device(int dev) | |
96 | +{ | |
97 | + struct mmc *mmc; | |
98 | + mmc = find_mmc_device(dev); | |
99 | + if (!mmc) { | |
100 | + printf("no mmc device at slot %x\n", dev); | |
101 | + return NULL; | |
102 | + } | |
103 | + if (mmc_init(mmc)) | |
104 | + return NULL; | |
105 | + return mmc; | |
106 | +} | |
102 | 107 | static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
103 | 108 | { |
104 | 109 | struct mmc *mmc; |
105 | 110 | |
106 | 111 | |
107 | 112 | |
108 | 113 | |
109 | 114 | |
110 | 115 | |
111 | 116 | |
112 | 117 | |
113 | 118 | |
114 | 119 | |
115 | 120 | |
116 | 121 | |
117 | 122 | |
118 | 123 | |
119 | 124 | |
120 | 125 | |
121 | 126 | |
122 | 127 | |
123 | 128 | |
124 | 129 | |
125 | 130 | |
126 | 131 | |
127 | 132 | |
128 | 133 | |
129 | 134 | |
130 | 135 | |
131 | 136 | |
132 | 137 | |
133 | 138 | |
134 | 139 | |
135 | 140 | |
136 | 141 | |
137 | 142 | |
138 | 143 | |
139 | 144 | |
140 | 145 | |
141 | 146 | |
142 | 147 | |
143 | 148 | |
144 | 149 | |
145 | 150 | |
146 | 151 | |
147 | 152 | |
148 | 153 | |
149 | 154 | |
150 | 155 | |
151 | 156 | |
152 | 157 | |
153 | 158 | |
154 | 159 | |
155 | 160 | |
156 | 161 | |
157 | 162 | |
158 | 163 | |
159 | 164 | |
160 | 165 | |
161 | 166 | |
162 | 167 | |
163 | 168 | |
164 | 169 | |
... | ... | @@ -112,351 +117,537 @@ |
112 | 117 | } |
113 | 118 | } |
114 | 119 | |
115 | - mmc = find_mmc_device(curr_device); | |
120 | + mmc = init_mmc_device(curr_device); | |
121 | + if (!mmc) | |
122 | + return CMD_RET_FAILURE; | |
116 | 123 | |
117 | - if (mmc) { | |
118 | - mmc_init(mmc); | |
124 | + print_mmcinfo(mmc); | |
125 | + return CMD_RET_SUCCESS; | |
126 | +} | |
119 | 127 | |
120 | - print_mmcinfo(mmc); | |
121 | - return 0; | |
122 | - } else { | |
123 | - printf("no mmc device at slot %x\n", curr_device); | |
128 | +#ifdef CONFIG_SUPPORT_EMMC_RPMB | |
129 | +static int confirm_key_prog(void) | |
130 | +{ | |
131 | + puts("Warning: Programming authentication key can be done only once !\n" | |
132 | + " Use this command only if you are sure of what you are doing,\n" | |
133 | + "Really perform the key programming? <y/N> "); | |
134 | + if (confirm_yesno()) | |
124 | 135 | return 1; |
136 | + | |
137 | + puts("Authentication key programming aborted\n"); | |
138 | + return 0; | |
139 | +} | |
140 | +static int do_mmcrpmb_key(cmd_tbl_t *cmdtp, int flag, | |
141 | + int argc, char * const argv[]) | |
142 | +{ | |
143 | + void *key_addr; | |
144 | + struct mmc *mmc = find_mmc_device(curr_device); | |
145 | + | |
146 | + if (argc != 2) | |
147 | + return CMD_RET_USAGE; | |
148 | + | |
149 | + key_addr = (void *)simple_strtoul(argv[1], NULL, 16); | |
150 | + if (!confirm_key_prog()) | |
151 | + return CMD_RET_FAILURE; | |
152 | + if (mmc_rpmb_set_key(mmc, key_addr)) { | |
153 | + printf("ERROR - Key already programmed ?\n"); | |
154 | + return CMD_RET_FAILURE; | |
125 | 155 | } |
156 | + return CMD_RET_SUCCESS; | |
126 | 157 | } |
158 | +static int do_mmcrpmb_read(cmd_tbl_t *cmdtp, int flag, | |
159 | + int argc, char * const argv[]) | |
160 | +{ | |
161 | + u16 blk, cnt; | |
162 | + void *addr; | |
163 | + int n; | |
164 | + void *key_addr = NULL; | |
165 | + struct mmc *mmc = find_mmc_device(curr_device); | |
127 | 166 | |
128 | -U_BOOT_CMD( | |
129 | - mmcinfo, 1, 0, do_mmcinfo, | |
130 | - "display MMC info", | |
131 | - "- display info of the current MMC device" | |
132 | -); | |
167 | + if (argc < 4) | |
168 | + return CMD_RET_USAGE; | |
133 | 169 | |
134 | -static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
170 | + addr = (void *)simple_strtoul(argv[1], NULL, 16); | |
171 | + blk = simple_strtoul(argv[2], NULL, 16); | |
172 | + cnt = simple_strtoul(argv[3], NULL, 16); | |
173 | + | |
174 | + if (argc == 5) | |
175 | + key_addr = (void *)simple_strtoul(argv[4], NULL, 16); | |
176 | + | |
177 | + printf("\nMMC RPMB read: dev # %d, block # %d, count %d ... ", | |
178 | + curr_device, blk, cnt); | |
179 | + n = mmc_rpmb_read(mmc, addr, blk, cnt, key_addr); | |
180 | + | |
181 | + printf("%d RPMB blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR"); | |
182 | + if (n != cnt) | |
183 | + return CMD_RET_FAILURE; | |
184 | + return CMD_RET_SUCCESS; | |
185 | +} | |
186 | +static int do_mmcrpmb_write(cmd_tbl_t *cmdtp, int flag, | |
187 | + int argc, char * const argv[]) | |
135 | 188 | { |
136 | - enum mmc_state state; | |
189 | + u16 blk, cnt; | |
190 | + void *addr; | |
191 | + int n; | |
192 | + void *key_addr; | |
193 | + struct mmc *mmc = find_mmc_device(curr_device); | |
137 | 194 | |
138 | - if (argc < 2) | |
195 | + if (argc != 5) | |
139 | 196 | return CMD_RET_USAGE; |
140 | 197 | |
141 | - if (curr_device < 0) { | |
142 | - if (get_mmc_num() > 0) | |
143 | - curr_device = 0; | |
144 | - else { | |
145 | - puts("No MMC device available\n"); | |
146 | - return 1; | |
147 | - } | |
198 | + addr = (void *)simple_strtoul(argv[1], NULL, 16); | |
199 | + blk = simple_strtoul(argv[2], NULL, 16); | |
200 | + cnt = simple_strtoul(argv[3], NULL, 16); | |
201 | + key_addr = (void *)simple_strtoul(argv[4], NULL, 16); | |
202 | + | |
203 | + printf("\nMMC RPMB write: dev # %d, block # %d, count %d ... ", | |
204 | + curr_device, blk, cnt); | |
205 | + n = mmc_rpmb_write(mmc, addr, blk, cnt, key_addr); | |
206 | + | |
207 | + printf("%d RPMB blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR"); | |
208 | + if (n != cnt) | |
209 | + return CMD_RET_FAILURE; | |
210 | + return CMD_RET_SUCCESS; | |
211 | +} | |
212 | +static int do_mmcrpmb_counter(cmd_tbl_t *cmdtp, int flag, | |
213 | + int argc, char * const argv[]) | |
214 | +{ | |
215 | + unsigned long counter; | |
216 | + struct mmc *mmc = find_mmc_device(curr_device); | |
217 | + | |
218 | + if (mmc_rpmb_get_counter(mmc, &counter)) | |
219 | + return CMD_RET_FAILURE; | |
220 | + printf("RPMB Write counter= %lx\n", counter); | |
221 | + return CMD_RET_SUCCESS; | |
222 | +} | |
223 | + | |
224 | +static cmd_tbl_t cmd_rpmb[] = { | |
225 | + U_BOOT_CMD_MKENT(key, 2, 0, do_mmcrpmb_key, "", ""), | |
226 | + U_BOOT_CMD_MKENT(read, 5, 1, do_mmcrpmb_read, "", ""), | |
227 | + U_BOOT_CMD_MKENT(write, 5, 0, do_mmcrpmb_write, "", ""), | |
228 | + U_BOOT_CMD_MKENT(counter, 1, 1, do_mmcrpmb_counter, "", ""), | |
229 | +}; | |
230 | + | |
231 | +static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag, | |
232 | + int argc, char * const argv[]) | |
233 | +{ | |
234 | + cmd_tbl_t *cp; | |
235 | + struct mmc *mmc; | |
236 | + char original_part; | |
237 | + int ret; | |
238 | + | |
239 | + cp = find_cmd_tbl(argv[1], cmd_rpmb, ARRAY_SIZE(cmd_rpmb)); | |
240 | + | |
241 | + /* Drop the rpmb subcommand */ | |
242 | + argc--; | |
243 | + argv++; | |
244 | + | |
245 | + if (cp == NULL || argc > cp->maxargs) | |
246 | + return CMD_RET_USAGE; | |
247 | + if (flag == CMD_FLAG_REPEAT && !cp->repeatable) | |
248 | + return CMD_RET_SUCCESS; | |
249 | + | |
250 | + mmc = init_mmc_device(curr_device); | |
251 | + if (!mmc) | |
252 | + return CMD_RET_FAILURE; | |
253 | + | |
254 | + if (!(mmc->version & MMC_VERSION_MMC)) { | |
255 | + printf("It is not a EMMC device\n"); | |
256 | + return CMD_RET_FAILURE; | |
148 | 257 | } |
258 | + if (mmc->version < MMC_VERSION_4_41) { | |
259 | + printf("RPMB not supported before version 4.41\n"); | |
260 | + return CMD_RET_FAILURE; | |
261 | + } | |
262 | + /* Switch to the RPMB partition */ | |
263 | + original_part = mmc->part_num; | |
264 | + if (mmc->part_num != MMC_PART_RPMB) { | |
265 | + if (mmc_switch_part(curr_device, MMC_PART_RPMB) != 0) | |
266 | + return CMD_RET_FAILURE; | |
267 | + mmc->part_num = MMC_PART_RPMB; | |
268 | + } | |
269 | + ret = cp->cmd(cmdtp, flag, argc, argv); | |
149 | 270 | |
150 | - if (strcmp(argv[1], "rescan") == 0) { | |
151 | - struct mmc *mmc; | |
271 | + /* Return to original partition */ | |
272 | + if (mmc->part_num != original_part) { | |
273 | + if (mmc_switch_part(curr_device, original_part) != 0) | |
274 | + return CMD_RET_FAILURE; | |
275 | + mmc->part_num = original_part; | |
276 | + } | |
277 | + return ret; | |
278 | +} | |
279 | +#endif | |
152 | 280 | |
153 | - if (argc != 2) | |
154 | - return CMD_RET_USAGE; | |
281 | +static int do_mmc_read(cmd_tbl_t *cmdtp, int flag, | |
282 | + int argc, char * const argv[]) | |
283 | +{ | |
284 | + struct mmc *mmc; | |
285 | + u32 blk, cnt, n; | |
286 | + void *addr; | |
155 | 287 | |
156 | - mmc = find_mmc_device(curr_device); | |
157 | - if (!mmc) { | |
158 | - printf("no mmc device at slot %x\n", curr_device); | |
159 | - return 1; | |
160 | - } | |
288 | + if (argc != 4) | |
289 | + return CMD_RET_USAGE; | |
161 | 290 | |
162 | - mmc->has_init = 0; | |
291 | + addr = (void *)simple_strtoul(argv[1], NULL, 16); | |
292 | + blk = simple_strtoul(argv[2], NULL, 16); | |
293 | + cnt = simple_strtoul(argv[3], NULL, 16); | |
163 | 294 | |
164 | - if (mmc_init(mmc)) | |
165 | - return 1; | |
166 | - else | |
167 | - return 0; | |
168 | - } else if (strcmp(argv[1], "part") == 0) { | |
169 | - block_dev_desc_t *mmc_dev; | |
170 | - struct mmc *mmc; | |
295 | + mmc = init_mmc_device(curr_device); | |
296 | + if (!mmc) | |
297 | + return CMD_RET_FAILURE; | |
171 | 298 | |
172 | - if (argc != 2) | |
173 | - return CMD_RET_USAGE; | |
299 | + printf("\nMMC read: dev # %d, block # %d, count %d ... ", | |
300 | + curr_device, blk, cnt); | |
174 | 301 | |
175 | - mmc = find_mmc_device(curr_device); | |
176 | - if (!mmc) { | |
177 | - printf("no mmc device at slot %x\n", curr_device); | |
178 | - return 1; | |
179 | - } | |
180 | - mmc_init(mmc); | |
181 | - mmc_dev = mmc_get_dev(curr_device); | |
182 | - if (mmc_dev != NULL && | |
183 | - mmc_dev->type != DEV_TYPE_UNKNOWN) { | |
184 | - print_part(mmc_dev); | |
185 | - return 0; | |
186 | - } | |
302 | + n = mmc->block_dev.block_read(curr_device, blk, cnt, addr); | |
303 | + /* flush cache after read */ | |
304 | + flush_cache((ulong)addr, cnt * 512); /* FIXME */ | |
305 | + printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR"); | |
187 | 306 | |
188 | - puts("get mmc type error!\n"); | |
189 | - return 1; | |
190 | - } else if (strcmp(argv[1], "list") == 0) { | |
191 | - if (argc != 2) | |
192 | - return CMD_RET_USAGE; | |
193 | - print_mmc_devices('\n'); | |
194 | - return 0; | |
195 | - } else if (strcmp(argv[1], "dev") == 0) { | |
196 | - int dev, part = -1; | |
197 | - struct mmc *mmc; | |
307 | + return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; | |
308 | +} | |
309 | +static int do_mmc_write(cmd_tbl_t *cmdtp, int flag, | |
310 | + int argc, char * const argv[]) | |
311 | +{ | |
312 | + struct mmc *mmc; | |
313 | + u32 blk, cnt, n; | |
314 | + void *addr; | |
198 | 315 | |
199 | - if (argc == 2) | |
200 | - dev = curr_device; | |
201 | - else if (argc == 3) | |
202 | - dev = simple_strtoul(argv[2], NULL, 10); | |
203 | - else if (argc == 4) { | |
204 | - dev = (int)simple_strtoul(argv[2], NULL, 10); | |
205 | - part = (int)simple_strtoul(argv[3], NULL, 10); | |
206 | - if (part > PART_ACCESS_MASK) { | |
207 | - printf("#part_num shouldn't be larger" | |
208 | - " than %d\n", PART_ACCESS_MASK); | |
209 | - return 1; | |
210 | - } | |
211 | - } else | |
212 | - return CMD_RET_USAGE; | |
316 | + if (argc != 4) | |
317 | + return CMD_RET_USAGE; | |
213 | 318 | |
214 | - mmc = find_mmc_device(dev); | |
215 | - if (!mmc) { | |
216 | - printf("no mmc device at slot %x\n", dev); | |
217 | - return 1; | |
218 | - } | |
319 | + addr = (void *)simple_strtoul(argv[1], NULL, 16); | |
320 | + blk = simple_strtoul(argv[2], NULL, 16); | |
321 | + cnt = simple_strtoul(argv[3], NULL, 16); | |
219 | 322 | |
220 | - mmc_init(mmc); | |
221 | - if (part != -1) { | |
222 | - int ret; | |
223 | - if (mmc->part_config == MMCPART_NOAVAILABLE) { | |
224 | - printf("Card doesn't support part_switch\n"); | |
225 | - return 1; | |
226 | - } | |
323 | + mmc = init_mmc_device(curr_device); | |
324 | + if (!mmc) | |
325 | + return CMD_RET_FAILURE; | |
227 | 326 | |
228 | - if (part != mmc->part_num) { | |
229 | - ret = mmc_switch_part(dev, part); | |
230 | - if (!ret) | |
231 | - mmc->part_num = part; | |
327 | + printf("\nMMC write: dev # %d, block # %d, count %d ... ", | |
328 | + curr_device, blk, cnt); | |
232 | 329 | |
233 | - printf("switch to partitions #%d, %s\n", | |
234 | - part, (!ret) ? "OK" : "ERROR"); | |
235 | - } | |
236 | - } | |
237 | - curr_device = dev; | |
238 | - if (mmc->part_config == MMCPART_NOAVAILABLE) | |
239 | - printf("mmc%d is current device\n", curr_device); | |
240 | - else | |
241 | - printf("mmc%d(part %d) is current device\n", | |
242 | - curr_device, mmc->part_num); | |
330 | + if (mmc_getwp(mmc) == 1) { | |
331 | + printf("Error: card is write protected!\n"); | |
332 | + return CMD_RET_FAILURE; | |
333 | + } | |
334 | + n = mmc->block_dev.block_write(curr_device, blk, cnt, addr); | |
335 | + printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR"); | |
243 | 336 | |
244 | - return 0; | |
245 | -#ifdef CONFIG_SUPPORT_EMMC_BOOT | |
246 | - } else if (strcmp(argv[1], "partconf") == 0) { | |
247 | - int dev; | |
248 | - struct mmc *mmc; | |
249 | - u8 ack, part_num, access; | |
337 | + return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; | |
338 | +} | |
339 | +static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag, | |
340 | + int argc, char * const argv[]) | |
341 | +{ | |
342 | + struct mmc *mmc; | |
343 | + u32 blk, cnt, n; | |
250 | 344 | |
251 | - if (argc == 6) { | |
252 | - dev = simple_strtoul(argv[2], NULL, 10); | |
253 | - ack = simple_strtoul(argv[3], NULL, 10); | |
254 | - part_num = simple_strtoul(argv[4], NULL, 10); | |
255 | - access = simple_strtoul(argv[5], NULL, 10); | |
256 | - } else { | |
257 | - return CMD_RET_USAGE; | |
258 | - } | |
345 | + if (argc != 3) | |
346 | + return CMD_RET_USAGE; | |
259 | 347 | |
260 | - mmc = find_mmc_device(dev); | |
261 | - if (!mmc) { | |
262 | - printf("no mmc device at slot %x\n", dev); | |
263 | - return 1; | |
264 | - } | |
348 | + blk = simple_strtoul(argv[1], NULL, 16); | |
349 | + cnt = simple_strtoul(argv[2], NULL, 16); | |
265 | 350 | |
266 | - if (IS_SD(mmc)) { | |
267 | - puts("PARTITION_CONFIG only exists on eMMC\n"); | |
268 | - return 1; | |
269 | - } | |
351 | + mmc = init_mmc_device(curr_device); | |
352 | + if (!mmc) | |
353 | + return CMD_RET_FAILURE; | |
270 | 354 | |
271 | - /* acknowledge to be sent during boot operation */ | |
272 | - return mmc_set_part_conf(mmc, ack, part_num, access); | |
273 | - } else if (strcmp(argv[1], "bootbus") == 0) { | |
274 | - int dev; | |
275 | - struct mmc *mmc; | |
276 | - u8 width, reset, mode; | |
355 | + printf("\nMMC erase: dev # %d, block # %d, count %d ... ", | |
356 | + curr_device, blk, cnt); | |
277 | 357 | |
278 | - if (argc == 6) { | |
279 | - dev = simple_strtoul(argv[2], NULL, 10); | |
280 | - width = simple_strtoul(argv[3], NULL, 10); | |
281 | - reset = simple_strtoul(argv[4], NULL, 10); | |
282 | - mode = simple_strtoul(argv[5], NULL, 10); | |
283 | - } else { | |
284 | - return CMD_RET_USAGE; | |
285 | - } | |
358 | + if (mmc_getwp(mmc) == 1) { | |
359 | + printf("Error: card is write protected!\n"); | |
360 | + return CMD_RET_FAILURE; | |
361 | + } | |
362 | + n = mmc->block_dev.block_erase(curr_device, blk, cnt); | |
363 | + printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR"); | |
286 | 364 | |
287 | - mmc = find_mmc_device(dev); | |
288 | - if (!mmc) { | |
289 | - printf("no mmc device at slot %x\n", dev); | |
290 | - return 1; | |
291 | - } | |
365 | + return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; | |
366 | +} | |
367 | +static int do_mmc_rescan(cmd_tbl_t *cmdtp, int flag, | |
368 | + int argc, char * const argv[]) | |
369 | +{ | |
370 | + struct mmc *mmc; | |
292 | 371 | |
293 | - if (IS_SD(mmc)) { | |
294 | - puts("BOOT_BUS_WIDTH only exists on eMMC\n"); | |
295 | - return 1; | |
296 | - } | |
372 | + mmc = find_mmc_device(curr_device); | |
373 | + if (!mmc) { | |
374 | + printf("no mmc device at slot %x\n", curr_device); | |
375 | + return CMD_RET_FAILURE; | |
376 | + } | |
297 | 377 | |
298 | - /* acknowledge to be sent during boot operation */ | |
299 | - return mmc_set_boot_bus_width(mmc, width, reset, mode); | |
300 | - } else if (strcmp(argv[1], "bootpart-resize") == 0) { | |
301 | - int dev; | |
302 | - struct mmc *mmc; | |
303 | - u32 bootsize, rpmbsize; | |
378 | + mmc->has_init = 0; | |
304 | 379 | |
305 | - if (argc == 5) { | |
306 | - dev = simple_strtoul(argv[2], NULL, 10); | |
307 | - bootsize = simple_strtoul(argv[3], NULL, 10); | |
308 | - rpmbsize = simple_strtoul(argv[4], NULL, 10); | |
309 | - } else { | |
310 | - return CMD_RET_USAGE; | |
311 | - } | |
380 | + if (mmc_init(mmc)) | |
381 | + return CMD_RET_FAILURE; | |
382 | + return CMD_RET_SUCCESS; | |
383 | +} | |
384 | +static int do_mmc_part(cmd_tbl_t *cmdtp, int flag, | |
385 | + int argc, char * const argv[]) | |
386 | +{ | |
387 | + block_dev_desc_t *mmc_dev; | |
388 | + struct mmc *mmc; | |
312 | 389 | |
313 | - mmc = find_mmc_device(dev); | |
314 | - if (!mmc) { | |
315 | - printf("no mmc device at slot %x\n", dev); | |
316 | - return 1; | |
317 | - } | |
390 | + mmc = init_mmc_device(curr_device); | |
391 | + if (!mmc) | |
392 | + return CMD_RET_FAILURE; | |
318 | 393 | |
319 | - if (IS_SD(mmc)) { | |
320 | - printf("It is not a EMMC device\n"); | |
321 | - return 1; | |
322 | - } | |
394 | + mmc_dev = mmc_get_dev(curr_device); | |
395 | + if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) { | |
396 | + print_part(mmc_dev); | |
397 | + return CMD_RET_SUCCESS; | |
398 | + } | |
323 | 399 | |
324 | - if (0 == mmc_boot_partition_size_change(mmc, | |
325 | - bootsize, rpmbsize)) { | |
326 | - printf("EMMC boot partition Size %d MB\n", bootsize); | |
327 | - printf("EMMC RPMB partition Size %d MB\n", rpmbsize); | |
328 | - return 0; | |
329 | - } else { | |
330 | - printf("EMMC boot partition Size change Failed.\n"); | |
331 | - return 1; | |
332 | - } | |
333 | - } else if (strcmp(argv[1], "rst-function") == 0) { | |
334 | - /* | |
335 | - * Set the RST_n_ENABLE bit of RST_n_FUNCTION | |
336 | - * The only valid values are 0x0, 0x1 and 0x2 and writing | |
337 | - * a value of 0x1 or 0x2 sets the value permanently. | |
338 | - */ | |
339 | - int dev; | |
340 | - struct mmc *mmc; | |
341 | - u8 enable; | |
400 | + puts("get mmc type error!\n"); | |
401 | + return CMD_RET_FAILURE; | |
402 | +} | |
403 | +static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag, | |
404 | + int argc, char * const argv[]) | |
405 | +{ | |
406 | + int dev, part = -1, ret; | |
407 | + struct mmc *mmc; | |
342 | 408 | |
343 | - if (argc == 4) { | |
344 | - dev = simple_strtoul(argv[2], NULL, 10); | |
345 | - enable = simple_strtoul(argv[3], NULL, 10); | |
346 | - } else { | |
347 | - return CMD_RET_USAGE; | |
409 | + if (argc == 1) { | |
410 | + dev = curr_device; | |
411 | + } else if (argc == 2) { | |
412 | + dev = simple_strtoul(argv[1], NULL, 10); | |
413 | + } else if (argc == 3) { | |
414 | + dev = (int)simple_strtoul(argv[1], NULL, 10); | |
415 | + part = (int)simple_strtoul(argv[2], NULL, 10); | |
416 | + if (part > PART_ACCESS_MASK) { | |
417 | + printf("#part_num shouldn't be larger than %d\n", | |
418 | + PART_ACCESS_MASK); | |
419 | + return CMD_RET_FAILURE; | |
348 | 420 | } |
421 | + } else { | |
422 | + return CMD_RET_USAGE; | |
423 | + } | |
349 | 424 | |
350 | - if (enable > 2 || enable < 0) { | |
351 | - puts("Invalid RST_n_ENABLE value\n"); | |
352 | - return CMD_RET_USAGE; | |
353 | - } | |
425 | + mmc = init_mmc_device(dev); | |
426 | + if (!mmc) | |
427 | + return CMD_RET_FAILURE; | |
354 | 428 | |
355 | - mmc = find_mmc_device(dev); | |
356 | - if (!mmc) { | |
357 | - printf("no mmc device at slot %x\n", dev); | |
429 | + if (part != -1) { | |
430 | + ret = mmc_select_hwpart(dev, part); | |
431 | + printf("switch to partitions #%d, %s\n", | |
432 | + part, (!ret) ? "OK" : "ERROR"); | |
433 | + if (ret) | |
358 | 434 | return 1; |
359 | - } | |
435 | + } | |
436 | + curr_device = dev; | |
437 | + if (mmc->part_config == MMCPART_NOAVAILABLE) | |
438 | + printf("mmc%d is current device\n", curr_device); | |
439 | + else | |
440 | + printf("mmc%d(part %d) is current device\n", | |
441 | + curr_device, mmc->part_num); | |
360 | 442 | |
361 | - if (IS_SD(mmc)) { | |
362 | - puts("RST_n_FUNCTION only exists on eMMC\n"); | |
363 | - return 1; | |
364 | - } | |
443 | + return CMD_RET_SUCCESS; | |
444 | +} | |
445 | +static int do_mmc_list(cmd_tbl_t *cmdtp, int flag, | |
446 | + int argc, char * const argv[]) | |
447 | +{ | |
448 | + print_mmc_devices('\n'); | |
449 | + return CMD_RET_SUCCESS; | |
450 | +} | |
451 | +#ifdef CONFIG_SUPPORT_EMMC_BOOT | |
452 | +static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag, | |
453 | + int argc, char * const argv[]) | |
454 | +{ | |
455 | + int dev; | |
456 | + struct mmc *mmc; | |
457 | + u8 width, reset, mode; | |
365 | 458 | |
366 | - return mmc_set_rst_n_function(mmc, enable); | |
367 | -#endif /* CONFIG_SUPPORT_EMMC_BOOT */ | |
459 | + if (argc != 5) | |
460 | + return CMD_RET_USAGE; | |
461 | + dev = simple_strtoul(argv[1], NULL, 10); | |
462 | + width = simple_strtoul(argv[2], NULL, 10); | |
463 | + reset = simple_strtoul(argv[3], NULL, 10); | |
464 | + mode = simple_strtoul(argv[4], NULL, 10); | |
465 | + | |
466 | + mmc = init_mmc_device(dev); | |
467 | + if (!mmc) | |
468 | + return CMD_RET_FAILURE; | |
469 | + | |
470 | + if (IS_SD(mmc)) { | |
471 | + puts("BOOT_BUS_WIDTH only exists on eMMC\n"); | |
472 | + return CMD_RET_FAILURE; | |
368 | 473 | } |
369 | 474 | |
370 | - else if (argc == 3 && strcmp(argv[1], "setdsr") == 0) { | |
371 | - struct mmc *mmc = find_mmc_device(curr_device); | |
372 | - u32 val = simple_strtoul(argv[2], NULL, 16); | |
373 | - int ret; | |
475 | + /* acknowledge to be sent during boot operation */ | |
476 | + return mmc_set_boot_bus_width(mmc, width, reset, mode); | |
477 | +} | |
478 | +static int do_mmc_boot_resize(cmd_tbl_t *cmdtp, int flag, | |
479 | + int argc, char * const argv[]) | |
480 | +{ | |
481 | + int dev; | |
482 | + struct mmc *mmc; | |
483 | + u32 bootsize, rpmbsize; | |
374 | 484 | |
375 | - if (!mmc) { | |
376 | - printf("no mmc device at slot %x\n", curr_device); | |
377 | - return 1; | |
378 | - } | |
379 | - ret = mmc_set_dsr(mmc, val); | |
380 | - printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR"); | |
381 | - if (!ret) { | |
382 | - mmc->has_init = 0; | |
383 | - if (mmc_init(mmc)) | |
384 | - return 1; | |
385 | - else | |
386 | - return 0; | |
387 | - } | |
388 | - return ret; | |
485 | + if (argc != 4) | |
486 | + return CMD_RET_USAGE; | |
487 | + dev = simple_strtoul(argv[1], NULL, 10); | |
488 | + bootsize = simple_strtoul(argv[2], NULL, 10); | |
489 | + rpmbsize = simple_strtoul(argv[3], NULL, 10); | |
490 | + | |
491 | + mmc = init_mmc_device(dev); | |
492 | + if (!mmc) | |
493 | + return CMD_RET_FAILURE; | |
494 | + | |
495 | + if (IS_SD(mmc)) { | |
496 | + printf("It is not a EMMC device\n"); | |
497 | + return CMD_RET_FAILURE; | |
389 | 498 | } |
390 | 499 | |
391 | - state = MMC_INVALID; | |
392 | - if (argc == 5 && strcmp(argv[1], "read") == 0) | |
393 | - state = MMC_READ; | |
394 | - else if (argc == 5 && strcmp(argv[1], "write") == 0) | |
395 | - state = MMC_WRITE; | |
396 | - else if (argc == 4 && strcmp(argv[1], "erase") == 0) | |
397 | - state = MMC_ERASE; | |
500 | + if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) { | |
501 | + printf("EMMC boot partition Size change Failed.\n"); | |
502 | + return CMD_RET_FAILURE; | |
503 | + } | |
398 | 504 | |
399 | - if (state != MMC_INVALID) { | |
400 | - struct mmc *mmc = find_mmc_device(curr_device); | |
401 | - int idx = 2; | |
402 | - u32 blk, cnt, n; | |
403 | - void *addr; | |
505 | + printf("EMMC boot partition Size %d MB\n", bootsize); | |
506 | + printf("EMMC RPMB partition Size %d MB\n", rpmbsize); | |
507 | + return CMD_RET_SUCCESS; | |
508 | +} | |
509 | +static int do_mmc_partconf(cmd_tbl_t *cmdtp, int flag, | |
510 | + int argc, char * const argv[]) | |
511 | +{ | |
512 | + int dev; | |
513 | + struct mmc *mmc; | |
514 | + u8 ack, part_num, access; | |
404 | 515 | |
405 | - if (state != MMC_ERASE) { | |
406 | - addr = (void *)simple_strtoul(argv[idx], NULL, 16); | |
407 | - ++idx; | |
408 | - } else | |
409 | - addr = NULL; | |
410 | - blk = simple_strtoul(argv[idx], NULL, 16); | |
411 | - cnt = simple_strtoul(argv[idx + 1], NULL, 16); | |
516 | + if (argc != 5) | |
517 | + return CMD_RET_USAGE; | |
412 | 518 | |
413 | - if (!mmc) { | |
414 | - printf("no mmc device at slot %x\n", curr_device); | |
415 | - return 1; | |
416 | - } | |
519 | + dev = simple_strtoul(argv[1], NULL, 10); | |
520 | + ack = simple_strtoul(argv[2], NULL, 10); | |
521 | + part_num = simple_strtoul(argv[3], NULL, 10); | |
522 | + access = simple_strtoul(argv[4], NULL, 10); | |
417 | 523 | |
418 | - printf("\nMMC %s: dev # %d, block # %d, count %d ... ", | |
419 | - argv[1], curr_device, blk, cnt); | |
524 | + mmc = init_mmc_device(dev); | |
525 | + if (!mmc) | |
526 | + return CMD_RET_FAILURE; | |
420 | 527 | |
421 | - mmc_init(mmc); | |
528 | + if (IS_SD(mmc)) { | |
529 | + puts("PARTITION_CONFIG only exists on eMMC\n"); | |
530 | + return CMD_RET_FAILURE; | |
531 | + } | |
422 | 532 | |
423 | - if ((state == MMC_WRITE || state == MMC_ERASE)) { | |
424 | - if (mmc_getwp(mmc) == 1) { | |
425 | - printf("Error: card is write protected!\n"); | |
426 | - return 1; | |
427 | - } | |
428 | - } | |
533 | + /* acknowledge to be sent during boot operation */ | |
534 | + return mmc_set_part_conf(mmc, ack, part_num, access); | |
535 | +} | |
536 | +static int do_mmc_rst_func(cmd_tbl_t *cmdtp, int flag, | |
537 | + int argc, char * const argv[]) | |
538 | +{ | |
539 | + int dev; | |
540 | + struct mmc *mmc; | |
541 | + u8 enable; | |
429 | 542 | |
430 | - switch (state) { | |
431 | - case MMC_READ: | |
432 | - n = mmc->block_dev.block_read(curr_device, blk, | |
433 | - cnt, addr); | |
434 | - /* flush cache after read */ | |
435 | - flush_cache((ulong)addr, cnt * 512); /* FIXME */ | |
436 | - break; | |
437 | - case MMC_WRITE: | |
438 | - n = mmc->block_dev.block_write(curr_device, blk, | |
439 | - cnt, addr); | |
440 | - break; | |
441 | - case MMC_ERASE: | |
442 | - n = mmc->block_dev.block_erase(curr_device, blk, cnt); | |
443 | - break; | |
444 | - default: | |
445 | - BUG(); | |
446 | - } | |
543 | + /* | |
544 | + * Set the RST_n_ENABLE bit of RST_n_FUNCTION | |
545 | + * The only valid values are 0x0, 0x1 and 0x2 and writing | |
546 | + * a value of 0x1 or 0x2 sets the value permanently. | |
547 | + */ | |
548 | + if (argc != 3) | |
549 | + return CMD_RET_USAGE; | |
447 | 550 | |
448 | - printf("%d blocks %s: %s\n", | |
449 | - n, argv[1], (n == cnt) ? "OK" : "ERROR"); | |
450 | - return (n == cnt) ? 0 : 1; | |
551 | + dev = simple_strtoul(argv[1], NULL, 10); | |
552 | + enable = simple_strtoul(argv[2], NULL, 10); | |
553 | + | |
554 | + if (enable > 2 || enable < 0) { | |
555 | + puts("Invalid RST_n_ENABLE value\n"); | |
556 | + return CMD_RET_USAGE; | |
451 | 557 | } |
452 | 558 | |
453 | - return CMD_RET_USAGE; | |
559 | + mmc = init_mmc_device(dev); | |
560 | + if (!mmc) | |
561 | + return CMD_RET_FAILURE; | |
562 | + | |
563 | + if (IS_SD(mmc)) { | |
564 | + puts("RST_n_FUNCTION only exists on eMMC\n"); | |
565 | + return CMD_RET_FAILURE; | |
566 | + } | |
567 | + | |
568 | + return mmc_set_rst_n_function(mmc, enable); | |
454 | 569 | } |
570 | +#endif | |
571 | +static int do_mmc_setdsr(cmd_tbl_t *cmdtp, int flag, | |
572 | + int argc, char * const argv[]) | |
573 | +{ | |
574 | + struct mmc *mmc; | |
575 | + u32 val; | |
576 | + int ret; | |
455 | 577 | |
578 | + if (argc != 2) | |
579 | + return CMD_RET_USAGE; | |
580 | + val = simple_strtoul(argv[2], NULL, 16); | |
581 | + | |
582 | + mmc = find_mmc_device(curr_device); | |
583 | + if (!mmc) { | |
584 | + printf("no mmc device at slot %x\n", curr_device); | |
585 | + return CMD_RET_FAILURE; | |
586 | + } | |
587 | + ret = mmc_set_dsr(mmc, val); | |
588 | + printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR"); | |
589 | + if (!ret) { | |
590 | + mmc->has_init = 0; | |
591 | + if (mmc_init(mmc)) | |
592 | + return CMD_RET_FAILURE; | |
593 | + else | |
594 | + return CMD_RET_SUCCESS; | |
595 | + } | |
596 | + return ret; | |
597 | +} | |
598 | + | |
599 | +static cmd_tbl_t cmd_mmc[] = { | |
600 | + U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""), | |
601 | + U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), | |
602 | + U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""), | |
603 | + U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""), | |
604 | + U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""), | |
605 | + U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""), | |
606 | + U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""), | |
607 | + U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""), | |
608 | +#ifdef CONFIG_SUPPORT_EMMC_BOOT | |
609 | + U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""), | |
610 | + U_BOOT_CMD_MKENT(bootpart-resize, 3, 0, do_mmc_boot_resize, "", ""), | |
611 | + U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""), | |
612 | + U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""), | |
613 | +#endif | |
614 | +#ifdef CONFIG_SUPPORT_EMMC_RPMB | |
615 | + U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""), | |
616 | +#endif | |
617 | + U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""), | |
618 | +}; | |
619 | + | |
620 | +static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
621 | +{ | |
622 | + cmd_tbl_t *cp; | |
623 | + | |
624 | + cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc)); | |
625 | + | |
626 | + /* Drop the mmc command */ | |
627 | + argc--; | |
628 | + argv++; | |
629 | + | |
630 | + if (cp == NULL || argc > cp->maxargs) | |
631 | + return CMD_RET_USAGE; | |
632 | + if (flag == CMD_FLAG_REPEAT && !cp->repeatable) | |
633 | + return CMD_RET_SUCCESS; | |
634 | + | |
635 | + if (curr_device < 0) { | |
636 | + if (get_mmc_num() > 0) { | |
637 | + curr_device = 0; | |
638 | + } else { | |
639 | + puts("No MMC device available\n"); | |
640 | + return CMD_RET_FAILURE; | |
641 | + } | |
642 | + } | |
643 | + return cp->cmd(cmdtp, flag, argc, argv); | |
644 | +} | |
645 | + | |
456 | 646 | U_BOOT_CMD( |
457 | - mmc, 6, 1, do_mmcops, | |
647 | + mmc, 7, 1, do_mmcops, | |
458 | 648 | "MMC sub system", |
459 | - "read addr blk# cnt\n" | |
649 | + "info - display info of the current MMC device\n" | |
650 | + "mmc read addr blk# cnt\n" | |
460 | 651 | "mmc write addr blk# cnt\n" |
461 | 652 | "mmc erase blk# cnt\n" |
462 | 653 | "mmc rescan\n" |
463 | 654 | |
... | ... | @@ -474,7 +665,21 @@ |
474 | 665 | " - Change the RST_n_FUNCTION field of the specified device\n" |
475 | 666 | " WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n" |
476 | 667 | #endif |
477 | - "mmc setdsr - set DSR register value\n" | |
668 | +#ifdef CONFIG_SUPPORT_EMMC_RPMB | |
669 | + "mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n" | |
670 | + "mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n" | |
671 | + "mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n" | |
672 | + "mmc rpmb counter - read the value of the write counter\n" | |
673 | +#endif | |
674 | + "mmc setdsr <value> - set DSR register value\n" | |
478 | 675 | ); |
676 | + | |
677 | +/* Old command kept for compatibility. Same as 'mmc info' */ | |
678 | +U_BOOT_CMD( | |
679 | + mmcinfo, 1, 0, do_mmcinfo, | |
680 | + "display MMC info", | |
681 | + "- display info of the current MMC device" | |
682 | +); | |
683 | + | |
479 | 684 | #endif /* !CONFIG_GENERIC_MMC */ |
common/cmd_nand.c
... | ... | @@ -605,22 +605,16 @@ |
605 | 605 | opts.spread = spread; |
606 | 606 | |
607 | 607 | if (scrub) { |
608 | - if (!scrub_yes) | |
609 | - puts(scrub_warn); | |
610 | - | |
611 | - if (scrub_yes) | |
608 | + if (scrub_yes) { | |
612 | 609 | opts.scrub = 1; |
613 | - else if (getc() == 'y') { | |
614 | - puts("y"); | |
615 | - if (getc() == '\r') | |
610 | + } else { | |
611 | + puts(scrub_warn); | |
612 | + if (confirm_yesno()) { | |
616 | 613 | opts.scrub = 1; |
617 | - else { | |
614 | + } else { | |
618 | 615 | puts("scrub aborted\n"); |
619 | 616 | return 1; |
620 | 617 | } |
621 | - } else { | |
622 | - puts("scrub aborted\n"); | |
623 | - return 1; | |
624 | 618 | } |
625 | 619 | } |
626 | 620 | ret = nand_erase_opts(nand, &opts); |
common/cmd_otp.c
... | ... | @@ -158,21 +158,9 @@ |
158 | 158 | lowup(half + count - 1), page + (half + count - 1) / 2, |
159 | 159 | half + count |
160 | 160 | ); |
161 | - | |
162 | - i = 0; | |
163 | - while (1) { | |
164 | - if (tstc()) { | |
165 | - const char exp_ans[] = "YES\r"; | |
166 | - char c; | |
167 | - putc(c = getc()); | |
168 | - if (exp_ans[i++] != c) { | |
169 | - printf(" Aborting\n"); | |
170 | - return 1; | |
171 | - } else if (!exp_ans[i]) { | |
172 | - puts("\n"); | |
173 | - break; | |
174 | - } | |
175 | - } | |
161 | + if (!confirm_yesno()) { | |
162 | + printf(" Aborting\n"); | |
163 | + return 1; | |
176 | 164 | } |
177 | 165 | } |
178 | 166 |
common/cmd_part.c
... | ... | @@ -82,7 +82,7 @@ |
82 | 82 | U_BOOT_CMD( |
83 | 83 | part, 5, 1, do_part, |
84 | 84 | "disk partition related commands", |
85 | - "uuid <interface> <dev>:<part>\n" | |
85 | + "part uuid <interface> <dev>:<part>\n" | |
86 | 86 | " - print partition UUID\n" |
87 | 87 | "part uuid <interface> <dev>:<part> <varname>\n" |
88 | 88 | " - set environment variable to partition UUID\n" |
common/console.c
... | ... | @@ -537,7 +537,33 @@ |
537 | 537 | } |
538 | 538 | return 0; |
539 | 539 | } |
540 | +/* Reads user's confirmation. | |
541 | + Returns 1 if user's input is "y", "Y", "yes" or "YES" | |
542 | +*/ | |
543 | +int confirm_yesno(void) | |
544 | +{ | |
545 | + int i; | |
546 | + char str_input[5]; | |
540 | 547 | |
548 | + /* Flush input */ | |
549 | + while (tstc()) | |
550 | + getc(); | |
551 | + i = 0; | |
552 | + while (i < sizeof(str_input)) { | |
553 | + str_input[i] = getc(); | |
554 | + putc(str_input[i]); | |
555 | + if (str_input[i] == '\r') | |
556 | + break; | |
557 | + i++; | |
558 | + } | |
559 | + putc('\n'); | |
560 | + if (strncmp(str_input, "y\r", 2) == 0 || | |
561 | + strncmp(str_input, "Y\r", 2) == 0 || | |
562 | + strncmp(str_input, "yes\r", 4) == 0 || | |
563 | + strncmp(str_input, "YES\r", 4) == 0) | |
564 | + return 1; | |
565 | + return 0; | |
566 | +} | |
541 | 567 | /* pass 1 to disable ctrlc() checking, 0 to enable. |
542 | 568 | * returns previous state |
543 | 569 | */ |
disk/part.c
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | struct block_drvr { |
23 | 23 | char *name; |
24 | 24 | block_dev_desc_t* (*get_dev)(int dev); |
25 | + int (*select_hwpart)(int dev_num, int hwpart); | |
25 | 26 | }; |
26 | 27 | |
27 | 28 | static const struct block_drvr block_drvr[] = { |
... | ... | @@ -38,7 +39,11 @@ |
38 | 39 | { .name = "usb", .get_dev = usb_stor_get_dev, }, |
39 | 40 | #endif |
40 | 41 | #if defined(CONFIG_MMC) |
41 | - { .name = "mmc", .get_dev = mmc_get_dev, }, | |
42 | + { | |
43 | + .name = "mmc", | |
44 | + .get_dev = mmc_get_dev, | |
45 | + .select_hwpart = mmc_select_hwpart, | |
46 | + }, | |
42 | 47 | #endif |
43 | 48 | #if defined(CONFIG_SYSTEMACE) |
44 | 49 | { .name = "ace", .get_dev = systemace_get_dev, }, |
45 | 50 | |
46 | 51 | |
... | ... | @@ -52,11 +57,13 @@ |
52 | 57 | DECLARE_GLOBAL_DATA_PTR; |
53 | 58 | |
54 | 59 | #ifdef HAVE_BLOCK_DEVICE |
55 | -block_dev_desc_t *get_dev(const char *ifname, int dev) | |
60 | +block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart) | |
56 | 61 | { |
57 | 62 | const struct block_drvr *drvr = block_drvr; |
58 | 63 | block_dev_desc_t* (*reloc_get_dev)(int dev); |
64 | + int (*select_hwpart)(int dev_num, int hwpart); | |
59 | 65 | char *name; |
66 | + int ret; | |
60 | 67 | |
61 | 68 | if (!ifname) |
62 | 69 | return NULL; |
63 | 70 | |
64 | 71 | |
65 | 72 | |
66 | 73 | |
... | ... | @@ -68,17 +75,41 @@ |
68 | 75 | while (drvr->name) { |
69 | 76 | name = drvr->name; |
70 | 77 | reloc_get_dev = drvr->get_dev; |
78 | + select_hwpart = drvr->select_hwpart; | |
71 | 79 | #ifdef CONFIG_NEEDS_MANUAL_RELOC |
72 | 80 | name += gd->reloc_off; |
73 | 81 | reloc_get_dev += gd->reloc_off; |
82 | + if (select_hwpart) | |
83 | + select_hwpart += gd->reloc_off; | |
74 | 84 | #endif |
75 | - if (strncmp(ifname, name, strlen(name)) == 0) | |
76 | - return reloc_get_dev(dev); | |
85 | + if (strncmp(ifname, name, strlen(name)) == 0) { | |
86 | + block_dev_desc_t *dev_desc = reloc_get_dev(dev); | |
87 | + if (!dev_desc) | |
88 | + return NULL; | |
89 | + if (hwpart == -1) | |
90 | + return dev_desc; | |
91 | + if (!select_hwpart) | |
92 | + return NULL; | |
93 | + ret = select_hwpart(dev_desc->dev, hwpart); | |
94 | + if (ret < 0) | |
95 | + return NULL; | |
96 | + return dev_desc; | |
97 | + } | |
77 | 98 | drvr++; |
78 | 99 | } |
79 | 100 | return NULL; |
80 | 101 | } |
102 | + | |
103 | +block_dev_desc_t *get_dev(const char *ifname, int dev) | |
104 | +{ | |
105 | + return get_dev_hwpart(ifname, dev, -1); | |
106 | +} | |
81 | 107 | #else |
108 | +block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart) | |
109 | +{ | |
110 | + return NULL; | |
111 | +} | |
112 | + | |
82 | 113 | block_dev_desc_t *get_dev(const char *ifname, int dev) |
83 | 114 | { |
84 | 115 | return NULL; |
85 | 116 | |
86 | 117 | |
87 | 118 | |
88 | 119 | |
89 | 120 | |
90 | 121 | |
... | ... | @@ -413,25 +444,52 @@ |
413 | 444 | return -1; |
414 | 445 | } |
415 | 446 | |
416 | -int get_device(const char *ifname, const char *dev_str, | |
447 | +int get_device(const char *ifname, const char *dev_hwpart_str, | |
417 | 448 | block_dev_desc_t **dev_desc) |
418 | 449 | { |
419 | 450 | char *ep; |
420 | - int dev; | |
451 | + char *dup_str = NULL; | |
452 | + const char *dev_str, *hwpart_str; | |
453 | + int dev, hwpart; | |
421 | 454 | |
455 | + hwpart_str = strchr(dev_hwpart_str, '.'); | |
456 | + if (hwpart_str) { | |
457 | + dup_str = strdup(dev_hwpart_str); | |
458 | + dup_str[hwpart_str - dev_hwpart_str] = 0; | |
459 | + dev_str = dup_str; | |
460 | + hwpart_str++; | |
461 | + } else { | |
462 | + dev_str = dev_hwpart_str; | |
463 | + hwpart = -1; | |
464 | + } | |
465 | + | |
422 | 466 | dev = simple_strtoul(dev_str, &ep, 16); |
423 | 467 | if (*ep) { |
424 | 468 | printf("** Bad device specification %s %s **\n", |
425 | 469 | ifname, dev_str); |
426 | - return -1; | |
470 | + dev = -1; | |
471 | + goto cleanup; | |
427 | 472 | } |
428 | 473 | |
429 | - *dev_desc = get_dev(ifname, dev); | |
474 | + if (hwpart_str) { | |
475 | + hwpart = simple_strtoul(hwpart_str, &ep, 16); | |
476 | + if (*ep) { | |
477 | + printf("** Bad HW partition specification %s %s **\n", | |
478 | + ifname, hwpart_str); | |
479 | + dev = -1; | |
480 | + goto cleanup; | |
481 | + } | |
482 | + } | |
483 | + | |
484 | + *dev_desc = get_dev_hwpart(ifname, dev, hwpart); | |
430 | 485 | if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { |
431 | - printf("** Bad device %s %s **\n", ifname, dev_str); | |
432 | - return -1; | |
486 | + printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); | |
487 | + dev = -1; | |
488 | + goto cleanup; | |
433 | 489 | } |
434 | 490 | |
491 | +cleanup: | |
492 | + free(dup_str); | |
435 | 493 | return dev; |
436 | 494 | } |
437 | 495 |
drivers/mmc/Makefile
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o |
31 | 31 | obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o |
32 | 32 | obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o |
33 | +obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o | |
33 | 34 | ifdef CONFIG_SPL_BUILD |
34 | 35 | obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o |
35 | 36 | else |
drivers/mmc/fsl_esdhc.c
... | ... | @@ -174,7 +174,7 @@ |
174 | 174 | int timeout; |
175 | 175 | struct fsl_esdhc_cfg *cfg = mmc->priv; |
176 | 176 | struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; |
177 | -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | |
177 | + | |
178 | 178 | uint wml_value; |
179 | 179 | |
180 | 180 | wml_value = data->blocksize/4; |
181 | 181 | |
182 | 182 | |
183 | 183 | |
... | ... | @@ -184,12 +184,15 @@ |
184 | 184 | wml_value = WML_RD_WML_MAX_VAL; |
185 | 185 | |
186 | 186 | esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); |
187 | +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | |
187 | 188 | esdhc_write32(®s->dsaddr, (u32)data->dest); |
189 | +#endif | |
188 | 190 | } else { |
191 | +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | |
189 | 192 | flush_dcache_range((ulong)data->src, |
190 | 193 | (ulong)data->src+data->blocks |
191 | 194 | *data->blocksize); |
192 | - | |
195 | +#endif | |
193 | 196 | if (wml_value > WML_WR_WML_MAX) |
194 | 197 | wml_value = WML_WR_WML_MAX_VAL; |
195 | 198 | if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { |
196 | 199 | |
197 | 200 | |
... | ... | @@ -199,19 +202,10 @@ |
199 | 202 | |
200 | 203 | esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, |
201 | 204 | wml_value << 16); |
205 | +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO | |
202 | 206 | esdhc_write32(®s->dsaddr, (u32)data->src); |
207 | +#endif | |
203 | 208 | } |
204 | -#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */ | |
205 | - if (!(data->flags & MMC_DATA_READ)) { | |
206 | - if ((esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { | |
207 | - printf("\nThe SD card is locked. " | |
208 | - "Can not write to a locked card.\n\n"); | |
209 | - return TIMEOUT; | |
210 | - } | |
211 | - esdhc_write32(®s->dsaddr, (u32)data->src); | |
212 | - } else | |
213 | - esdhc_write32(®s->dsaddr, (u32)data->dest); | |
214 | -#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */ | |
215 | 209 | |
216 | 210 | esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); |
217 | 211 | |
218 | 212 | |
... | ... | @@ -388,9 +382,10 @@ |
388 | 382 | goto out; |
389 | 383 | } |
390 | 384 | } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); |
391 | -#endif | |
385 | + | |
392 | 386 | if (data->flags & MMC_DATA_READ) |
393 | 387 | check_and_invalidate_dcache_range(cmd, data); |
388 | +#endif | |
394 | 389 | } |
395 | 390 | |
396 | 391 | out: |
drivers/mmc/mmc.c
... | ... | @@ -150,6 +150,8 @@ |
150 | 150 | #endif |
151 | 151 | return TIMEOUT; |
152 | 152 | } |
153 | + if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) | |
154 | + return SWITCH_ERR; | |
153 | 155 | |
154 | 156 | return 0; |
155 | 157 | } |
... | ... | @@ -501,7 +503,7 @@ |
501 | 503 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); |
502 | 504 | |
503 | 505 | if (err) |
504 | - return err; | |
506 | + return err == SWITCH_ERR ? 0 : err; | |
505 | 507 | |
506 | 508 | /* Now check to see that it worked */ |
507 | 509 | err = mmc_send_ext_csd(mmc, ext_csd); |
... | ... | @@ -550,6 +552,32 @@ |
550 | 552 | return 0; |
551 | 553 | } |
552 | 554 | |
555 | +int mmc_select_hwpart(int dev_num, int hwpart) | |
556 | +{ | |
557 | + struct mmc *mmc = find_mmc_device(dev_num); | |
558 | + int ret; | |
559 | + | |
560 | + if (!mmc) | |
561 | + return -1; | |
562 | + | |
563 | + if (mmc->part_num == hwpart) | |
564 | + return 0; | |
565 | + | |
566 | + if (mmc->part_config == MMCPART_NOAVAILABLE) { | |
567 | + printf("Card doesn't support part_switch\n"); | |
568 | + return -1; | |
569 | + } | |
570 | + | |
571 | + ret = mmc_switch_part(dev_num, hwpart); | |
572 | + if (ret) | |
573 | + return -1; | |
574 | + | |
575 | + mmc->part_num = hwpart; | |
576 | + | |
577 | + return 0; | |
578 | +} | |
579 | + | |
580 | + | |
553 | 581 | int mmc_switch_part(int dev_num, unsigned int part_num) |
554 | 582 | { |
555 | 583 | struct mmc *mmc = find_mmc_device(dev_num); |
556 | 584 | |
... | ... | @@ -1310,10 +1338,13 @@ |
1310 | 1338 | int mmc_init(struct mmc *mmc) |
1311 | 1339 | { |
1312 | 1340 | int err = IN_PROGRESS; |
1313 | - unsigned start = get_timer(0); | |
1341 | + unsigned start; | |
1314 | 1342 | |
1315 | 1343 | if (mmc->has_init) |
1316 | 1344 | return 0; |
1345 | + | |
1346 | + start = get_timer(0); | |
1347 | + | |
1317 | 1348 | if (!mmc->init_in_progress) |
1318 | 1349 | err = mmc_start_init(mmc); |
1319 | 1350 |
drivers/mmc/rpmb.c
1 | +/* | |
2 | + * Copyright 2014, Staubli Faverges | |
3 | + * Pierre Aubert | |
4 | + * | |
5 | + * eMMC- Replay Protected Memory Block | |
6 | + * According to JEDEC Standard No. 84-A441 | |
7 | + * | |
8 | + * SPDX-License-Identifier: GPL-2.0+ | |
9 | + */ | |
10 | + | |
11 | +#include <config.h> | |
12 | +#include <common.h> | |
13 | +#include <mmc.h> | |
14 | +#include <sha256.h> | |
15 | +#include "mmc_private.h" | |
16 | + | |
17 | +/* Request codes */ | |
18 | +#define RPMB_REQ_KEY 1 | |
19 | +#define RPMB_REQ_WCOUNTER 2 | |
20 | +#define RPMB_REQ_WRITE_DATA 3 | |
21 | +#define RPMB_REQ_READ_DATA 4 | |
22 | +#define RPMB_REQ_STATUS 5 | |
23 | + | |
24 | +/* Response code */ | |
25 | +#define RPMB_RESP_KEY 0x0100 | |
26 | +#define RPMB_RESP_WCOUNTER 0x0200 | |
27 | +#define RPMB_RESP_WRITE_DATA 0x0300 | |
28 | +#define RPMB_RESP_READ_DATA 0x0400 | |
29 | + | |
30 | +/* Error codes */ | |
31 | +#define RPMB_OK 0 | |
32 | +#define RPMB_ERR_GENERAL 1 | |
33 | +#define RPMB_ERR_AUTH 2 | |
34 | +#define RPMB_ERR_COUNTER 3 | |
35 | +#define RPMB_ERR_ADDRESS 4 | |
36 | +#define RPMB_ERR_WRITE 5 | |
37 | +#define RPMB_ERR_READ 6 | |
38 | +#define RPMB_ERR_KEY 7 | |
39 | +#define RPMB_ERR_CNT_EXPIRED 0x80 | |
40 | +#define RPMB_ERR_MSK 0x7 | |
41 | + | |
42 | +/* Sizes of RPMB data frame */ | |
43 | +#define RPMB_SZ_STUFF 196 | |
44 | +#define RPMB_SZ_MAC 32 | |
45 | +#define RPMB_SZ_DATA 256 | |
46 | +#define RPMB_SZ_NONCE 16 | |
47 | + | |
48 | +#define SHA256_BLOCK_SIZE 64 | |
49 | + | |
50 | +/* Error messages */ | |
51 | +static const char * const rpmb_err_msg[] = { | |
52 | + "", | |
53 | + "General failure", | |
54 | + "Authentication failure", | |
55 | + "Counter failure", | |
56 | + "Address failure", | |
57 | + "Write failure", | |
58 | + "Read failure", | |
59 | + "Authentication key not yet programmed", | |
60 | +}; | |
61 | + | |
62 | + | |
63 | +/* Structure of RPMB data frame. */ | |
64 | +struct s_rpmb { | |
65 | + unsigned char stuff[RPMB_SZ_STUFF]; | |
66 | + unsigned char mac[RPMB_SZ_MAC]; | |
67 | + unsigned char data[RPMB_SZ_DATA]; | |
68 | + unsigned char nonce[RPMB_SZ_NONCE]; | |
69 | + unsigned long write_counter; | |
70 | + unsigned short address; | |
71 | + unsigned short block_count; | |
72 | + unsigned short result; | |
73 | + unsigned short request; | |
74 | +}; | |
75 | + | |
76 | +static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount, | |
77 | + bool is_rel_write) | |
78 | +{ | |
79 | + struct mmc_cmd cmd = {0}; | |
80 | + | |
81 | + cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT; | |
82 | + cmd.cmdarg = blockcount & 0x0000FFFF; | |
83 | + if (is_rel_write) | |
84 | + cmd.cmdarg |= 1 << 31; | |
85 | + cmd.resp_type = MMC_RSP_R1; | |
86 | + | |
87 | + return mmc_send_cmd(mmc, &cmd, NULL); | |
88 | +} | |
89 | +static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, | |
90 | + unsigned int count, bool is_rel_write) | |
91 | +{ | |
92 | + struct mmc_cmd cmd = {0}; | |
93 | + struct mmc_data data; | |
94 | + int ret; | |
95 | + | |
96 | + ret = mmc_set_blockcount(mmc, count, is_rel_write); | |
97 | + if (ret) { | |
98 | +#ifdef CONFIG_MMC_RPMB_TRACE | |
99 | + printf("%s:mmc_set_blockcount-> %d\n", __func__, ret); | |
100 | +#endif | |
101 | + return 1; | |
102 | + } | |
103 | + | |
104 | + cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; | |
105 | + cmd.cmdarg = 0; | |
106 | + cmd.resp_type = MMC_RSP_R1b; | |
107 | + | |
108 | + data.src = (const char *)s; | |
109 | + data.blocks = 1; | |
110 | + data.blocksize = MMC_MAX_BLOCK_LEN; | |
111 | + data.flags = MMC_DATA_WRITE; | |
112 | + | |
113 | + ret = mmc_send_cmd(mmc, &cmd, &data); | |
114 | + if (ret) { | |
115 | +#ifdef CONFIG_MMC_RPMB_TRACE | |
116 | + printf("%s:mmc_send_cmd-> %d\n", __func__, ret); | |
117 | +#endif | |
118 | + return 1; | |
119 | + } | |
120 | + return 0; | |
121 | +} | |
122 | +static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s, | |
123 | + unsigned short expected) | |
124 | +{ | |
125 | + struct mmc_cmd cmd = {0}; | |
126 | + struct mmc_data data; | |
127 | + int ret; | |
128 | + | |
129 | + ret = mmc_set_blockcount(mmc, 1, false); | |
130 | + if (ret) { | |
131 | +#ifdef CONFIG_MMC_RPMB_TRACE | |
132 | + printf("%s:mmc_set_blockcount-> %d\n", __func__, ret); | |
133 | +#endif | |
134 | + return -1; | |
135 | + } | |
136 | + cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; | |
137 | + cmd.cmdarg = 0; | |
138 | + cmd.resp_type = MMC_RSP_R1; | |
139 | + | |
140 | + data.dest = (char *)s; | |
141 | + data.blocks = 1; | |
142 | + data.blocksize = MMC_MAX_BLOCK_LEN; | |
143 | + data.flags = MMC_DATA_READ; | |
144 | + | |
145 | + ret = mmc_send_cmd(mmc, &cmd, &data); | |
146 | + if (ret) { | |
147 | +#ifdef CONFIG_MMC_RPMB_TRACE | |
148 | + printf("%s:mmc_send_cmd-> %d\n", __func__, ret); | |
149 | +#endif | |
150 | + return -1; | |
151 | + } | |
152 | + /* Check the response and the status */ | |
153 | + if (be16_to_cpu(s->request) != expected) { | |
154 | +#ifdef CONFIG_MMC_RPMB_TRACE | |
155 | + printf("%s:response= %x\n", __func__, | |
156 | + be16_to_cpu(s->request)); | |
157 | +#endif | |
158 | + return -1; | |
159 | + } | |
160 | + ret = be16_to_cpu(s->result); | |
161 | + if (ret) { | |
162 | + printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK], | |
163 | + (ret & RPMB_ERR_CNT_EXPIRED) ? | |
164 | + "Write counter has expired" : ""); | |
165 | + } | |
166 | + | |
167 | + /* Return the status of the command */ | |
168 | + return ret; | |
169 | +} | |
170 | +static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected) | |
171 | +{ | |
172 | + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); | |
173 | + | |
174 | + memset(rpmb_frame, 0, sizeof(struct s_rpmb)); | |
175 | + rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS); | |
176 | + if (mmc_rpmb_request(mmc, rpmb_frame, 1, false)) | |
177 | + return -1; | |
178 | + | |
179 | + /* Read the result */ | |
180 | + return mmc_rpmb_response(mmc, rpmb_frame, expected); | |
181 | +} | |
182 | +static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len, | |
183 | + unsigned char *output) | |
184 | +{ | |
185 | + sha256_context ctx; | |
186 | + int i; | |
187 | + unsigned char k_ipad[SHA256_BLOCK_SIZE]; | |
188 | + unsigned char k_opad[SHA256_BLOCK_SIZE]; | |
189 | + | |
190 | + sha256_starts(&ctx); | |
191 | + | |
192 | + /* According to RFC 4634, the HMAC transform looks like: | |
193 | + SHA(K XOR opad, SHA(K XOR ipad, text)) | |
194 | + | |
195 | + where K is an n byte key. | |
196 | + ipad is the byte 0x36 repeated blocksize times | |
197 | + opad is the byte 0x5c repeated blocksize times | |
198 | + and text is the data being protected. | |
199 | + */ | |
200 | + | |
201 | + for (i = 0; i < RPMB_SZ_MAC; i++) { | |
202 | + k_ipad[i] = key[i] ^ 0x36; | |
203 | + k_opad[i] = key[i] ^ 0x5c; | |
204 | + } | |
205 | + /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ | |
206 | + for ( ; i < SHA256_BLOCK_SIZE; i++) { | |
207 | + k_ipad[i] = 0x36; | |
208 | + k_opad[i] = 0x5c; | |
209 | + } | |
210 | + sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE); | |
211 | + sha256_update(&ctx, buff, len); | |
212 | + sha256_finish(&ctx, output); | |
213 | + | |
214 | + /* Init context for second pass */ | |
215 | + sha256_starts(&ctx); | |
216 | + | |
217 | + /* start with outer pad */ | |
218 | + sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE); | |
219 | + | |
220 | + /* then results of 1st hash */ | |
221 | + sha256_update(&ctx, output, RPMB_SZ_MAC); | |
222 | + | |
223 | + /* finish up 2nd pass */ | |
224 | + sha256_finish(&ctx, output); | |
225 | +} | |
226 | +int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter) | |
227 | +{ | |
228 | + int ret; | |
229 | + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); | |
230 | + | |
231 | + /* Fill the request */ | |
232 | + memset(rpmb_frame, 0, sizeof(struct s_rpmb)); | |
233 | + rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER); | |
234 | + if (mmc_rpmb_request(mmc, rpmb_frame, 1, false)) | |
235 | + return -1; | |
236 | + | |
237 | + /* Read the result */ | |
238 | + ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER); | |
239 | + if (ret) | |
240 | + return ret; | |
241 | + | |
242 | + *pcounter = be32_to_cpu(rpmb_frame->write_counter); | |
243 | + return 0; | |
244 | +} | |
245 | +int mmc_rpmb_set_key(struct mmc *mmc, void *key) | |
246 | +{ | |
247 | + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); | |
248 | + /* Fill the request */ | |
249 | + memset(rpmb_frame, 0, sizeof(struct s_rpmb)); | |
250 | + rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY); | |
251 | + memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC); | |
252 | + | |
253 | + if (mmc_rpmb_request(mmc, rpmb_frame, 1, true)) | |
254 | + return -1; | |
255 | + | |
256 | + /* read the operation status */ | |
257 | + return mmc_rpmb_status(mmc, RPMB_RESP_KEY); | |
258 | +} | |
259 | +int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, | |
260 | + unsigned short cnt, unsigned char *key) | |
261 | +{ | |
262 | + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); | |
263 | + int i; | |
264 | + | |
265 | + for (i = 0; i < cnt; i++) { | |
266 | + /* Fill the request */ | |
267 | + memset(rpmb_frame, 0, sizeof(struct s_rpmb)); | |
268 | + rpmb_frame->address = cpu_to_be16(blk + i); | |
269 | + rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA); | |
270 | + if (mmc_rpmb_request(mmc, rpmb_frame, 1, false)) | |
271 | + break; | |
272 | + | |
273 | + /* Read the result */ | |
274 | + if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA)) | |
275 | + break; | |
276 | + | |
277 | + /* Check the HMAC if key is provided */ | |
278 | + if (key) { | |
279 | + unsigned char ret_hmac[RPMB_SZ_MAC]; | |
280 | + | |
281 | + rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac); | |
282 | + if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) { | |
283 | + printf("MAC error on block #%d\n", i); | |
284 | + break; | |
285 | + } | |
286 | + } | |
287 | + /* Copy data */ | |
288 | + memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA); | |
289 | + } | |
290 | + return i; | |
291 | +} | |
292 | +int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, | |
293 | + unsigned short cnt, unsigned char *key) | |
294 | +{ | |
295 | + ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); | |
296 | + unsigned long wcount; | |
297 | + int i; | |
298 | + | |
299 | + for (i = 0; i < cnt; i++) { | |
300 | + if (mmc_rpmb_get_counter(mmc, &wcount)) { | |
301 | + printf("Cannot read RPMB write counter\n"); | |
302 | + break; | |
303 | + } | |
304 | + | |
305 | + /* Fill the request */ | |
306 | + memset(rpmb_frame, 0, sizeof(struct s_rpmb)); | |
307 | + memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA); | |
308 | + rpmb_frame->address = cpu_to_be16(blk + i); | |
309 | + rpmb_frame->block_count = cpu_to_be16(1); | |
310 | + rpmb_frame->write_counter = cpu_to_be32(wcount); | |
311 | + rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA); | |
312 | + /* Computes HMAC */ | |
313 | + rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac); | |
314 | + | |
315 | + if (mmc_rpmb_request(mmc, rpmb_frame, 1, true)) | |
316 | + break; | |
317 | + | |
318 | + /* Get status */ | |
319 | + if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA)) | |
320 | + break; | |
321 | + } | |
322 | + return i; | |
323 | +} |
include/common.h
... | ... | @@ -836,7 +836,7 @@ |
836 | 836 | int had_ctrlc (void); /* have we had a Control-C since last clear? */ |
837 | 837 | void clear_ctrlc (void); /* clear the Control-C condition */ |
838 | 838 | int disable_ctrlc (int); /* 1 to disable, 0 to enable Control-C detect */ |
839 | - | |
839 | +int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */ | |
840 | 840 | /* |
841 | 841 | * STDIO based functions (can always be used) |
842 | 842 | */ |
include/configs/kwb.h
... | ... | @@ -109,7 +109,7 @@ |
109 | 109 | |
110 | 110 | #undef CONFIG_ENV_IS_NOWHERE |
111 | 111 | #define CONFIG_ENV_IS_IN_MMC |
112 | -#define CONFIG_SYS_MMC_ENV_DEV 1 | |
112 | +#define CONFIG_SYS_MMC_ENV_DEV 0 | |
113 | 113 | #define CONFIG_SYS_MMC_ENV_PART 2 |
114 | 114 | #define CONFIG_ENV_OFFSET 0x40000 /* TODO: Adresse definieren */ |
115 | 115 | #define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) |
include/configs/tseries.h
... | ... | @@ -237,7 +237,7 @@ |
237 | 237 | #elif defined(CONFIG_EMMC_BOOT) |
238 | 238 | #undef CONFIG_ENV_IS_NOWHERE |
239 | 239 | #define CONFIG_ENV_IS_IN_MMC |
240 | -#define CONFIG_SYS_MMC_ENV_DEV 1 | |
240 | +#define CONFIG_SYS_MMC_ENV_DEV 0 | |
241 | 241 | #define CONFIG_SYS_MMC_ENV_PART 2 |
242 | 242 | #define CONFIG_ENV_OFFSET 0x40000 /* TODO: Adresse definieren */ |
243 | 243 | #define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE) |
include/mmc.h
... | ... | @@ -54,6 +54,7 @@ |
54 | 54 | #define COMM_ERR -18 /* Communications Error */ |
55 | 55 | #define TIMEOUT -19 |
56 | 56 | #define IN_PROGRESS -20 /* operation is in progress */ |
57 | +#define SWITCH_ERR -21 /* Card reports failure to switch mode */ | |
57 | 58 | |
58 | 59 | #define MMC_CMD_GO_IDLE_STATE 0 |
59 | 60 | #define MMC_CMD_SEND_OP_COND 1 |
... | ... | @@ -70,6 +71,7 @@ |
70 | 71 | #define MMC_CMD_SET_BLOCKLEN 16 |
71 | 72 | #define MMC_CMD_READ_SINGLE_BLOCK 17 |
72 | 73 | #define MMC_CMD_READ_MULTIPLE_BLOCK 18 |
74 | +#define MMC_CMD_SET_BLOCK_COUNT 23 | |
73 | 75 | #define MMC_CMD_WRITE_SINGLE_BLOCK 24 |
74 | 76 | #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 |
75 | 77 | #define MMC_CMD_ERASE_GROUP_START 35 |
... | ... | @@ -109,6 +111,7 @@ |
109 | 111 | #define SECURE_ERASE 0x80000000 |
110 | 112 | |
111 | 113 | #define MMC_STATUS_MASK (~0x0206BF7F) |
114 | +#define MMC_STATUS_SWITCH_ERROR (1 << 7) | |
112 | 115 | #define MMC_STATUS_RDY_FOR_DATA (1 << 8) |
113 | 116 | #define MMC_STATUS_CURR_STATE (0xf << 9) |
114 | 117 | #define MMC_STATUS_ERROR (1 << 19) |
... | ... | @@ -225,6 +228,7 @@ |
225 | 228 | * boot partitions (2), general purpose partitions (4) in MMC v4.4. |
226 | 229 | */ |
227 | 230 | #define MMC_NUM_BOOT_PARTITION 2 |
231 | +#define MMC_PART_RPMB 3 /* RPMB partition number */ | |
228 | 232 | |
229 | 233 | struct mmc_cid { |
230 | 234 | unsigned long psn; |
... | ... | @@ -336,7 +340,13 @@ |
336 | 340 | int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode); |
337 | 341 | /* Function to modify the RST_n_FUNCTION field of EXT_CSD */ |
338 | 342 | int mmc_set_rst_n_function(struct mmc *mmc, u8 enable); |
339 | - | |
343 | +/* Functions to read / write the RPMB partition */ | |
344 | +int mmc_rpmb_set_key(struct mmc *mmc, void *key); | |
345 | +int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *counter); | |
346 | +int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, | |
347 | + unsigned short cnt, unsigned char *key); | |
348 | +int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, | |
349 | + unsigned short cnt, unsigned char *key); | |
340 | 350 | /** |
341 | 351 | * Start device initialization and return immediately; it does not block on |
342 | 352 | * polling OCR (operation condition register) status. Then you should call |
include/part.h
... | ... | @@ -103,6 +103,7 @@ |
103 | 103 | block_dev_desc_t* scsi_get_dev(int dev); |
104 | 104 | block_dev_desc_t* usb_stor_get_dev(int dev); |
105 | 105 | block_dev_desc_t* mmc_get_dev(int dev); |
106 | +int mmc_select_hwpart(int dev_num, int hwpart); | |
106 | 107 | block_dev_desc_t* systemace_get_dev(int dev); |
107 | 108 | block_dev_desc_t* mg_disk_get_dev(int dev); |
108 | 109 | block_dev_desc_t *host_get_dev(int dev); |
... | ... | @@ -126,6 +127,7 @@ |
126 | 127 | static inline block_dev_desc_t* scsi_get_dev(int dev) { return NULL; } |
127 | 128 | static inline block_dev_desc_t* usb_stor_get_dev(int dev) { return NULL; } |
128 | 129 | static inline block_dev_desc_t* mmc_get_dev(int dev) { return NULL; } |
130 | +static inline int mmc_select_hwpart(int dev_num, int hwpart) { return -1; } | |
129 | 131 | static inline block_dev_desc_t* systemace_get_dev(int dev) { return NULL; } |
130 | 132 | static inline block_dev_desc_t* mg_disk_get_dev(int dev) { return NULL; } |
131 | 133 | static inline block_dev_desc_t *host_get_dev(int dev) { return NULL; } |
lib/Makefile