1 /*
2 * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved.
3 * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * Neither the name of ARM nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <arch_helpers.h>
33 #include <assert.h>
34 #include <debug.h>
35 #include <dw_mmc.h>
36 #include <fastboot.h>
37 #include <io_block.h>
38 #include <io_driver.h>
39 #include <io_fip.h>
40 #include <io_memmap.h>
41 #include <io_storage.h>
42 #include <mmio.h>
43 #include <partitions.h>
44 #include <platform_def.h>
45 #include <semihosting.h> /* For FOPEN_MODE_... */
46 #include <string.h>
47 #include "hikey_private.h"
48
49 #define LOADER_MAX_ENTRIES 2
50 #define PTABLE_MAX_ENTRIES 3
51 #define USER_MAX_ENTRIES 2
52
53 #define FLUSH_BASE (DDR_BASE + 0x100000)
54
55 struct entry_head {
56 unsigned char magic[8];
57 unsigned char name[8];
58 unsigned int start; /* lba */
59 unsigned int count; /* lba */
60 unsigned int flag;
61 };
62
63 static const io_dev_connector_t *bl1_mem_dev_con;
64 static uintptr_t bl1_mem_dev_spec;
65 static uintptr_t loader_mem_dev_handle;
66 static uintptr_t bl1_mem_init_params;
67 static const io_dev_connector_t *fip_dev_con;
68 static uintptr_t fip_dev_spec;
69 static uintptr_t fip_dev_handle;
70 static const io_dev_connector_t *dw_mmc_dev_con;
71 static struct block_ops dw_mmc_ops;
72 static uintptr_t emmc_dev_handle;
73
74 #define SPARSE_FILL_BUFFER_ADDRESS 0x18000000
75 #define SPARSE_FILL_BUFFER_SIZE 0x08000000
76
77 /* Page 1024, since only a few pages before 2048 are used as partition table */
78 #define SERIALNO_OFFSET (1024 * 512)
79
80 static const io_block_spec_t loader_mem_spec = {
81 /* l-loader.bin that contains bl1.bin */
82 .offset = LOADER_RAM_BASE,
83 .length = BL1_RO_LIMIT - LOADER_RAM_BASE,
84 };
85
86 static const io_block_spec_t boot_emmc_spec = {
87 .offset = MMC_LOADER_BASE,
88 .length = BL1_RO_LIMIT - LOADER_RAM_BASE,
89 };
90
91 static const io_block_spec_t normal_emmc_spec = {
92 .offset = MMC_BASE,
93 .length = MMC_SIZE,
94 };
95
96 static io_block_spec_t fip_block_spec = {
97 .offset = 0,
98 .length = 0,
99 };
100
101 static const io_file_spec_t bl2_file_spec = {
102 .path = BL2_IMAGE_NAME,
103 .mode = FOPEN_MODE_RB
104 };
105
106 static const io_file_spec_t bl30_file_spec = {
107 .path = BL30_IMAGE_NAME,
108 .mode = FOPEN_MODE_RB
109 };
110
111 static const io_file_spec_t bl31_file_spec = {
112 .path = BL31_IMAGE_NAME,
113 .mode = FOPEN_MODE_RB
114 };
115
116 static const io_file_spec_t bl32_file_spec = {
117 .path = BL32_IMAGE_NAME,
118 .mode = FOPEN_MODE_RB
119 };
120
121 static const io_file_spec_t bl33_file_spec = {
122 .path = BL33_IMAGE_NAME,
123 .mode = FOPEN_MODE_RB
124 };
125
126 static int open_loader_mem(const uintptr_t spec);
127 static int open_fip(const uintptr_t spec);
128 static int open_dw_mmc(const uintptr_t spec);
129 static int open_dw_mmc_boot(const uintptr_t spec);
130
131 struct plat_io_policy {
132 const char *image_name;
133 uintptr_t *dev_handle;
134 uintptr_t image_spec;
135 int (*check)(const uintptr_t spec);
136 };
137
138 static const struct plat_io_policy policies[] = {
139 {
140 LOADER_MEM_NAME,
141 &loader_mem_dev_handle,
142 (uintptr_t)&loader_mem_spec,
143 open_loader_mem
144 }, {
145 BOOT_EMMC_NAME,
146 &emmc_dev_handle,
147 (uintptr_t)&boot_emmc_spec,
148 open_dw_mmc_boot
149 }, {
150 NORMAL_EMMC_NAME,
151 &emmc_dev_handle,
152 (uintptr_t)&normal_emmc_spec,
153 open_dw_mmc
154 }, {
155 FIP_IMAGE_NAME,
156 &emmc_dev_handle,
157 (uintptr_t)&fip_block_spec,
158 open_dw_mmc
159 }, {
160 BL2_IMAGE_NAME,
161 &fip_dev_handle,
162 (uintptr_t)&bl2_file_spec,
163 open_fip
164 }, {
165 BL30_IMAGE_NAME,
166 &fip_dev_handle,
167 (uintptr_t)&bl30_file_spec,
168 open_fip
169 }, {
170 BL31_IMAGE_NAME,
171 &fip_dev_handle,
172 (uintptr_t)&bl31_file_spec,
173 open_fip
174 }, {
175 BL32_IMAGE_NAME,
176 &fip_dev_handle,
177 (uintptr_t)&bl32_file_spec,
178 open_fip
179 }, {
180 BL33_IMAGE_NAME,
181 &fip_dev_handle,
182 (uintptr_t)&bl33_file_spec,
183 open_fip
184 }, {
185 0, 0, 0, 0
186 }
187 };
188
open_loader_mem(const uintptr_t spec)189 static int open_loader_mem(const uintptr_t spec)
190 {
191 int result = IO_FAIL;
192 uintptr_t image_handle;
193
194 result = io_dev_init(loader_mem_dev_handle, bl1_mem_init_params);
195 if (result == IO_SUCCESS) {
196 result = io_open(loader_mem_dev_handle, spec, &image_handle);
197 if (result == IO_SUCCESS) {
198 io_close(image_handle);
199 }
200 }
201 return result;
202 }
203
open_fip(const uintptr_t spec)204 static int open_fip(const uintptr_t spec)
205 {
206 int result = IO_FAIL;
207
208 /* See if a Firmware Image Package is available */
209 result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_NAME);
210 if (result == IO_SUCCESS) {
211 INFO("Using FIP\n");
212 /*TODO: Check image defined in spec is present in FIP. */
213 }
214 return result;
215 }
216
217
open_dw_mmc(const uintptr_t spec)218 static int open_dw_mmc(const uintptr_t spec)
219 {
220 int result = IO_FAIL;
221 uintptr_t image_handle;
222
223 /* indicate to select normal partition in eMMC */
224 result = io_dev_init(emmc_dev_handle, 0);
225 if (result == IO_SUCCESS) {
226 result = io_open(emmc_dev_handle, spec, &image_handle);
227 if (result == IO_SUCCESS) {
228 /* INFO("Using DW MMC IO\n"); */
229 io_close(image_handle);
230 }
231 }
232 return result;
233 }
234
open_dw_mmc_boot(const uintptr_t spec)235 static int open_dw_mmc_boot(const uintptr_t spec)
236 {
237 int result = IO_FAIL;
238 uintptr_t image_handle;
239
240 /* indicate to select boot partition in eMMC */
241 result = io_dev_init(emmc_dev_handle, 1);
242 if (result == IO_SUCCESS) {
243 result = io_open(emmc_dev_handle, spec, &image_handle);
244 if (result == IO_SUCCESS) {
245 /* INFO("Using DW MMC IO\n"); */
246 io_close(image_handle);
247 }
248 }
249 return result;
250 }
251
io_setup(void)252 void io_setup(void)
253 {
254 int io_result = IO_FAIL;
255
256 /* Register the IO devices on this platform */
257 io_result = register_io_dev_fip(&fip_dev_con);
258 assert(io_result == IO_SUCCESS);
259
260 io_result = register_io_dev_block(&dw_mmc_dev_con);
261 assert(io_result == IO_SUCCESS);
262
263 io_result = register_io_dev_memmap(&bl1_mem_dev_con);
264 assert(io_result == IO_SUCCESS);
265
266 /* Open connections to devices and cache the handles */
267 io_result = io_dev_open(fip_dev_con, fip_dev_spec, &fip_dev_handle);
268 assert(io_result == IO_SUCCESS);
269
270 dw_mmc_ops.init = init_mmc;
271 dw_mmc_ops.read = mmc0_read;
272 dw_mmc_ops.write = mmc0_write;
273 io_result = io_dev_open(dw_mmc_dev_con, (uintptr_t)&dw_mmc_ops,
274 &emmc_dev_handle);
275 assert(io_result == IO_SUCCESS);
276
277 io_result = io_dev_open(bl1_mem_dev_con, bl1_mem_dev_spec,
278 &loader_mem_dev_handle);
279 assert(io_result == IO_SUCCESS);
280
281 /* Ignore improbable errors in release builds */
282 (void)io_result;
283 }
284
285 /* Return an IO device handle and specification which can be used to access
286 * an image. Use this to enforce platform load policy */
plat_get_image_source(const char * image_name,uintptr_t * dev_handle,uintptr_t * image_spec)287 int plat_get_image_source(const char *image_name, uintptr_t *dev_handle,
288 uintptr_t *image_spec)
289 {
290 int result = IO_FAIL;
291 const struct plat_io_policy *policy;
292
293 if ((image_name != NULL) && (dev_handle != NULL) &&
294 (image_spec != NULL)) {
295 policy = policies;
296 while (policy->image_name != NULL) {
297 if (strcmp(policy->image_name, image_name) == 0) {
298 result = policy->check(policy->image_spec);
299 if (result == IO_SUCCESS) {
300 *image_spec = policy->image_spec;
301 *dev_handle = *(policy->dev_handle);
302 break;
303 }
304 }
305 policy++;
306 }
307 } else {
308 result = IO_FAIL;
309 }
310 return result;
311 }
312
update_fip_spec(void)313 int update_fip_spec(void)
314 {
315 struct ptentry *ptn;
316
317 ptn = find_ptn("fastboot");
318 if (!ptn) {
319 WARN("failed to find partition fastboot\n");
320 ptn = find_ptn("bios");
321 if (!ptn) {
322 WARN("failed to find partition bios\n");
323 return IO_FAIL;
324 }
325 }
326 VERBOSE("%s: name:%s, start:%llx, length:%llx\n",
327 __func__, ptn->name, ptn->start, ptn->length);
328 fip_block_spec.offset = ptn->start;
329 fip_block_spec.length = ptn->length;
330 return IO_SUCCESS;
331 }
332
fetch_entry_head(void * buf,int num,struct entry_head * hd)333 static int fetch_entry_head(void *buf, int num, struct entry_head *hd)
334 {
335 unsigned char magic[8] = "ENTRYHDR";
336 if (hd == NULL)
337 return IO_FAIL;
338 memcpy((void *)hd, buf, sizeof(struct entry_head) * num);
339 if (!strncmp((void *)hd->magic, (void *)magic, 8))
340 return IO_SUCCESS;
341 return IO_NOT_SUPPORTED;
342 }
343
flush_loader(void)344 static int flush_loader(void)
345 {
346 struct entry_head entries[5];
347 uintptr_t img_handle, spec;
348 int result = IO_FAIL;
349 size_t bytes_read, length;
350 ssize_t offset;
351 int i, fp;
352
353 result = fetch_entry_head((void *)(FLUSH_BASE + 28),
354 LOADER_MAX_ENTRIES, entries);
355 if (result) {
356 WARN("failed to parse entries in loader image\n");
357 return result;
358 }
359
360 spec = 0;
361 for (i = 0, fp = 0; i < LOADER_MAX_ENTRIES; i++) {
362 if (entries[i].flag != 1) {
363 WARN("Invalid flag in entry:0x%x\n", entries[i].flag);
364 return IO_NOT_SUPPORTED;
365 }
366 result = plat_get_image_source(BOOT_EMMC_NAME, &emmc_dev_handle,
367 &spec);
368 if (result) {
369 WARN("failed to open emmc boot area\n");
370 return result;
371 }
372 /* offset in Boot Area1 */
373 offset = MMC_LOADER_BASE + entries[i].start * 512;
374
375 result = io_open(emmc_dev_handle, spec, &img_handle);
376 if (result != IO_SUCCESS) {
377 WARN("Failed to open memmap device\n");
378 return result;
379 }
380 length = entries[i].count * 512;
381
382 result = io_seek(img_handle, IO_SEEK_SET, offset);
383 if (result)
384 goto exit;
385
386 if (i == 1)
387 fp = (entries[1].start - entries[0].start) * 512;
388 result = io_write(img_handle, FLUSH_BASE + fp, length,
389 &bytes_read);
390 if ((result != IO_SUCCESS) || (bytes_read < length)) {
391 WARN("Failed to write '%s' file (%i)\n",
392 LOADER_MEM_NAME, result);
393 goto exit;
394 }
395 io_close(img_handle);
396 }
397 return result;
398 exit:
399 io_close(img_handle);
400 return result;
401 }
402
403 /*
404 * Flush l-loader.bin (loader & bl1.bin) into Boot Area1 of eMMC.
405 */
flush_loader_image(void)406 int flush_loader_image(void)
407 {
408 uintptr_t bl1_image_spec;
409 int result = IO_FAIL;
410 size_t bytes_read, length;
411 uintptr_t img_handle;
412
413 result = plat_get_image_source(LOADER_MEM_NAME, &loader_mem_dev_handle,
414 &bl1_image_spec);
415
416 result = io_open(loader_mem_dev_handle, bl1_image_spec, &img_handle);
417 if (result != IO_SUCCESS) {
418 WARN("Failed to open memmap device\n");
419 goto exit;
420 }
421 length = loader_mem_spec.length;
422 result = io_read(img_handle, FLUSH_BASE, length, &bytes_read);
423 if ((result != IO_SUCCESS) || (bytes_read < length)) {
424 WARN("Failed to load '%s' file (%i)\n", LOADER_MEM_NAME, result);
425 goto exit;
426 }
427 io_close(img_handle);
428
429 result = flush_loader();
430 if (result != IO_SUCCESS) {
431 io_dev_close(loader_mem_dev_handle);
432 return result;
433 }
434 exit:
435 io_close(img_handle);
436 io_dev_close(loader_mem_dev_handle);
437 return result;
438 }
439
flush_single_image(const char * mmc_name,unsigned long img_addr,ssize_t offset,size_t length)440 static int flush_single_image(const char *mmc_name, unsigned long img_addr,
441 ssize_t offset, size_t length)
442 {
443 uintptr_t img_handle, spec = 0;
444 size_t bytes_read;
445 int result = IO_FAIL;
446
447 result = plat_get_image_source(mmc_name, &emmc_dev_handle,
448 &spec);
449 if (result) {
450 NOTICE("failed to open emmc user data area\n");
451 return result;
452 }
453
454 result = io_open(emmc_dev_handle, spec, &img_handle);
455 if (result != IO_SUCCESS) {
456 NOTICE("Failed to open memmap device\n");
457 return result;
458 }
459
460 result = io_seek(img_handle, IO_SEEK_SET, offset);
461 if (result) {
462 NOTICE("Failed to seek at offset:0x%x\n", offset);
463 goto exit;
464 }
465
466 result = io_write(img_handle, img_addr, length,
467 &bytes_read);
468 if ((result != IO_SUCCESS) || (bytes_read < length)) {
469 NOTICE("Failed to write file (%i)\n", result);
470 goto exit;
471 }
472 exit:
473 io_close(img_handle);
474 return result;
475 }
476
is_sparse_image(unsigned long img_addr)477 static int is_sparse_image(unsigned long img_addr)
478 {
479 if (*(uint32_t *)img_addr == SPARSE_HEADER_MAGIC)
480 return 1;
481 return 0;
482 }
483
do_unsparse(char * cmdbuf,unsigned long img_addr,unsigned long img_length)484 static int do_unsparse(char *cmdbuf, unsigned long img_addr, unsigned long img_length)
485 {
486 sparse_header_t *header = (sparse_header_t *)img_addr;
487 chunk_header_t *chunk = NULL;
488 struct ptentry *ptn;
489 void *data = (void *)img_addr;
490 uint64_t out_blks = 0, out_length = 0;
491 uint64_t length;
492 uint32_t fill_value;
493 uint64_t left, count;
494 int i, result;
495
496 ptn = find_ptn(cmdbuf);
497 if (!ptn) {
498 NOTICE("failed to find partition %s\n", cmdbuf);
499 return IO_FAIL;
500 }
501 length = (uint64_t)(header->total_blks) * (uint64_t)(header->blk_sz);
502 if (length > ptn->length) {
503 NOTICE("Unsparsed image length is %lld, pentry length is %lld.\n",
504 length, ptn->length);
505 return IO_FAIL;
506 }
507
508 data = (void *)((unsigned long)data + header->file_hdr_sz);
509 for (i = 0; i < header->total_chunks; i++) {
510 chunk = (chunk_header_t *)data;
511 data = (void *)((unsigned long)data + sizeof(chunk_header_t));
512 length = (uint64_t)chunk->chunk_sz * (uint64_t)header->blk_sz;
513
514 switch (chunk->chunk_type) {
515 case CHUNK_TYPE_RAW:
516 result = flush_single_image(NORMAL_EMMC_NAME,
517 (unsigned long)data,
518 ptn->start + out_length, length);
519 if (result < 0) {
520 NOTICE("sparse: failed to flush raw chunk\n");
521 return result;
522 }
523 out_blks += length / 512;
524 out_length += length;
525 /* next chunk is just after the raw data */
526 data = (void *)((unsigned long)data + length);
527 break;
528 case CHUNK_TYPE_FILL:
529 if (chunk->total_sz != (sizeof(unsigned int) + sizeof(chunk_header_t))) {
530 NOTICE("sparse: bad chunk size\n");
531 return IO_FAIL;
532 }
533 fill_value = *(unsigned int *)data;
534 if (fill_value != 0) {
535 NOTICE("sparse: filled value shouldn't be zero.\n");
536 }
537 memset((void *)SPARSE_FILL_BUFFER_ADDRESS,
538 0, SPARSE_FILL_BUFFER_SIZE);
539 left = length;
540 while (left > 0) {
541 if (left < SPARSE_FILL_BUFFER_SIZE)
542 count = left;
543 else
544 count = SPARSE_FILL_BUFFER_SIZE;
545 result = flush_single_image(NORMAL_EMMC_NAME,
546 SPARSE_FILL_BUFFER_ADDRESS,
547 ptn->start + out_length, count);
548 if (result < 0) {
549 WARN("sparse: failed to flush fill chunk\n");
550 return result;
551 }
552 out_blks += count / 512;
553 out_length += count;
554 left = left - count;
555 }
556 /* next chunk is just after the filled data */
557 data = (void *)((unsigned long)data + sizeof(unsigned int));
558 break;
559 case CHUNK_TYPE_DONT_CARE:
560 if (chunk->total_sz != sizeof(chunk_header_t)) {
561 NOTICE("sparse: unmatched chunk size\n");
562 return IO_FAIL;
563 }
564 out_blks += length / 512;
565 out_length += length;
566 break;
567 default:
568 NOTICE("sparse: unrecognized type 0x%x\n", chunk->chunk_type);
569 break;
570 }
571 }
572 return 0;
573 }
574
575 /* Page 1024 is used to store serial number */
flush_random_serialno(unsigned long addr,unsigned long length)576 int flush_random_serialno(unsigned long addr, unsigned long length)
577 {
578 int result;
579
580 memset((void *)SPARSE_FILL_BUFFER_ADDRESS, 0, 512);
581 memcpy((void *)SPARSE_FILL_BUFFER_ADDRESS, (void *)addr, length);
582 result = flush_single_image(NORMAL_EMMC_NAME, SPARSE_FILL_BUFFER_ADDRESS,
583 SERIALNO_OFFSET, 512);
584 return result;
585 }
586
load_serialno(void)587 char *load_serialno(void)
588 {
589 uintptr_t img_handle, spec = 0;
590 size_t bytes_read;
591 struct random_serial_num *random = NULL;
592 int result;
593
594 result = plat_get_image_source(NORMAL_EMMC_NAME, &emmc_dev_handle,
595 &spec);
596 if (result) {
597 NOTICE("failed to open emmc user data area\n");
598 return NULL;
599 }
600
601 result = io_open(emmc_dev_handle, spec, &img_handle);
602 if (result != IO_SUCCESS) {
603 NOTICE("Failed to open memmap device\n");
604 return NULL;
605 }
606
607 result = io_seek(img_handle, IO_SEEK_SET, SERIALNO_OFFSET);
608 if (result) {
609 NOTICE("Failed to seek at offset 0\n");
610 goto exit;
611 }
612 result = io_read(img_handle, SPARSE_FILL_BUFFER_ADDRESS, 512, &bytes_read);
613 if ((result != IO_SUCCESS) || (bytes_read < 512)) {
614 NOTICE("Failed to load '%s' file (%i)\n", LOADER_MEM_NAME, result);
615 goto exit;
616 }
617 io_close(img_handle);
618
619 random = (struct random_serial_num *)SPARSE_FILL_BUFFER_ADDRESS;
620 if (random->magic != RANDOM_MAGIC)
621 return NULL;
622
623 return random->serialno;
624 exit:
625 io_close(img_handle);
626 return NULL;
627 }
628
629 /*
630 * Flush bios.bin into User Data Area in eMMC
631 */
flush_user_images(char * cmdbuf,unsigned long img_addr,unsigned long img_length)632 int flush_user_images(char *cmdbuf, unsigned long img_addr,
633 unsigned long img_length)
634 {
635 struct entry_head entries[5];
636 struct ptentry *ptn;
637 size_t length;
638 ssize_t offset;
639 int result = IO_FAIL;
640 int i, fp;
641
642 result = fetch_entry_head((void *)img_addr, USER_MAX_ENTRIES, entries);
643 switch (result) {
644 case IO_NOT_SUPPORTED:
645 if (!strncmp(cmdbuf, "fastboot", 8) ||
646 !strncmp(cmdbuf, "bios", 4)) {
647 update_fip_spec();
648 }
649 if (is_sparse_image(img_addr)) {
650 result = do_unsparse(cmdbuf, img_addr, img_length);
651 } else {
652 ptn = find_ptn(cmdbuf);
653 if (!ptn) {
654 WARN("failed to find partition %s\n", cmdbuf);
655 return IO_FAIL;
656 }
657 img_length = (img_length + 512 - 1) / 512 * 512;
658 result = flush_single_image(NORMAL_EMMC_NAME, img_addr,
659 ptn->start, img_length);
660 }
661 break;
662 case IO_SUCCESS:
663 if (strncmp(cmdbuf, "ptable", 6)) {
664 WARN("it's not for ptable\n");
665 return IO_FAIL;
666 }
667 /* currently it's for partition table */
668 /* the first block is for entry headers */
669 fp = 512;
670
671 for (i = 0; i < USER_MAX_ENTRIES; i++) {
672 if (entries[i].flag != 0) {
673 WARN("Invalid flag in entry:0x%x\n",
674 entries[i].flag);
675 return IO_NOT_SUPPORTED;
676 }
677 if (entries[i].count == 0)
678 continue;
679 length = entries[i].count * 512;
680 offset = MMC_BASE + entries[i].start * 512;
681 VERBOSE("i:%d, start:%x, count:%x\n",
682 i, entries[i].start, entries[i].count);
683 result = flush_single_image(NORMAL_EMMC_NAME,
684 img_addr + fp, offset, length);
685 fp += entries[i].count * 512;
686 }
687 get_partition();
688 break;
689 case IO_FAIL:
690 WARN("failed to parse entries in user image.\n");
691 return result;
692 }
693 return result;
694 }
695