Commit 504a1e84654a8b4b7f6cc672417fcbfa8e2b18c1
1 parent
7163f0ca1c
Exists in
smarc-imx_v2017.03_o8.1.0_1.3.0_8m
and in
1 other branch
MA-11693-1 [Android]Support m4 image flash for imx7ulp and im8mq
Support m4 image flash by fastboot: 'fastboot flash m4_os <path-to-image>'. For 7ulp, m4 image will be excuted on POR and it doesn't depand on A core, so the m4 image will be flashed to nor flash using 'sf' command. For imx8m, m4 image will be loaded and excuted by A core. The m4 image will be flashed to physical 'm4_os' partition and can be excuted by 'bootmcu' command. Change-Id: I43bf0c9a484c5633cfe32dde3d738e33afdc775b Signed-off-by: Luo Ji <ji.luo@nxp.com>
Showing 3 changed files with 261 additions and 2 deletions Side-by-side Diff
arch/arm/imx-common/Kconfig
... | ... | @@ -79,6 +79,12 @@ |
79 | 79 | Select this to bind a ULP M4 image to final u-boot image |
80 | 80 | User needs put the M4 image ulp_m4.bin under u-boot directory |
81 | 81 | |
82 | +config FLASH_MCUFIRMWARE_SUPPORT | |
83 | + bool "Enable mcu firmware flash support" | |
84 | + depends on ARCH_MX7ULP || ARCH_IMX8M | |
85 | + help | |
86 | + This enables the mcu firmware flash support for some SOCs. | |
87 | + | |
82 | 88 | config IMX_TRUSTY_OS |
83 | 89 | bool "Support Trusty OS related feature" |
84 | 90 | depends on ARCH_MX6 || ARCH_MX7 |
drivers/usb/gadget/f_fastboot.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | #include <linux/compiler.h> |
26 | 26 | #include <version.h> |
27 | 27 | #include <g_dnl.h> |
28 | +#include "lib/avb/fsl/utils.h" | |
28 | 29 | #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV |
29 | 30 | #include <fb_mmc.h> |
30 | 31 | #endif |
... | ... | @@ -82,6 +83,10 @@ |
82 | 83 | |
83 | 84 | #define EP_BUFFER_SIZE 4096 |
84 | 85 | |
86 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
87 | +struct fastboot_device_info fastboot_firmwareinfo; | |
88 | +#endif | |
89 | + | |
85 | 90 | #if defined (CONFIG_ARCH_IMX8) || defined (CONFIG_ARCH_IMX8M) |
86 | 91 | #define DST_DECOMPRESS_LEN 1024*1024*32 |
87 | 92 | #endif |
... | ... | @@ -261,6 +266,9 @@ |
261 | 266 | enum { |
262 | 267 | PTN_GPT_INDEX = 0, |
263 | 268 | PTN_TEE_INDEX, |
269 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
270 | + PTN_M4_OS_INDEX, | |
271 | +#endif | |
264 | 272 | PTN_BOOTLOADER_INDEX, |
265 | 273 | }; |
266 | 274 | static unsigned int download_bytes_unpadded; |
... | ... | @@ -275,6 +283,98 @@ |
275 | 283 | .transfer_buffer_size = 0, |
276 | 284 | }; |
277 | 285 | |
286 | +int read_from_partition_multi(const char* partition, | |
287 | + int64_t offset, size_t num_bytes, void* buffer, size_t* out_num_read) | |
288 | +{ | |
289 | + struct fastboot_ptentry *pte; | |
290 | + unsigned char *bdata; | |
291 | + unsigned char *out_buf = (unsigned char *)buffer; | |
292 | + unsigned char *dst, *dst64 = NULL; | |
293 | + unsigned long blksz; | |
294 | + unsigned long s, cnt; | |
295 | + size_t num_read = 0; | |
296 | + lbaint_t part_start, part_end, bs, be, bm, blk_num; | |
297 | + margin_pos_t margin; | |
298 | + struct blk_desc *fs_dev_desc = NULL; | |
299 | + int dev_no; | |
300 | + int ret; | |
301 | + | |
302 | + assert(buffer != NULL && out_num_read != NULL); | |
303 | + | |
304 | + dev_no = mmc_get_env_dev(); | |
305 | + if ((fs_dev_desc = blk_get_dev("mmc", dev_no)) == NULL) { | |
306 | + printf("mmc device not found\n"); | |
307 | + return -1; | |
308 | + } | |
309 | + | |
310 | + pte = fastboot_flash_find_ptn(partition); | |
311 | + if (!pte) { | |
312 | + printf("no %s partition\n", partition); | |
313 | + return -1; | |
314 | + } | |
315 | + | |
316 | + blksz = fs_dev_desc->blksz; | |
317 | + part_start = pte->start; | |
318 | + part_end = pte->start + pte->length - 1; | |
319 | + | |
320 | + if (get_margin_pos((uint64_t)part_start, (uint64_t)part_end, blksz, | |
321 | + &margin, offset, num_bytes, true)) | |
322 | + return -1; | |
323 | + | |
324 | + bs = (lbaint_t)margin.blk_start; | |
325 | + be = (lbaint_t)margin.blk_end; | |
326 | + s = margin.start; | |
327 | + bm = margin.multi; | |
328 | + | |
329 | + /* alloc a blksz mem */ | |
330 | + bdata = (unsigned char *)memalign(ALIGN_BYTES, blksz); | |
331 | + if (bdata == NULL) { | |
332 | + printf("Failed to allocate memory!\n"); | |
333 | + return -1; | |
334 | + } | |
335 | + | |
336 | + /* support multi blk read */ | |
337 | + while (bs <= be) { | |
338 | + if (!s && bm > 1) { | |
339 | + dst = out_buf; | |
340 | + dst64 = PTR_ALIGN(out_buf, 64); /* for mmc blk read alignment */ | |
341 | + if (dst64 != dst) { | |
342 | + dst = dst64; | |
343 | + bm--; | |
344 | + } | |
345 | + blk_num = bm; | |
346 | + cnt = bm * blksz; | |
347 | + bm = 0; /* no more multi blk */ | |
348 | + } else { | |
349 | + blk_num = 1; | |
350 | + cnt = blksz - s; | |
351 | + if (num_read + cnt > num_bytes) | |
352 | + cnt = num_bytes - num_read; | |
353 | + dst = bdata; | |
354 | + } | |
355 | + if (!fs_dev_desc->block_read(fs_dev_desc, bs, blk_num, dst)) { | |
356 | + ret = -1; | |
357 | + goto fail; | |
358 | + } | |
359 | + | |
360 | + if (dst == bdata) | |
361 | + memcpy(out_buf, bdata + s, cnt); | |
362 | + else if (dst == dst64) | |
363 | + memcpy(out_buf, dst, cnt); /* internal copy */ | |
364 | + | |
365 | + s = 0; | |
366 | + bs += blk_num; | |
367 | + num_read += cnt; | |
368 | + out_buf += cnt; | |
369 | + } | |
370 | + *out_num_read = num_read; | |
371 | + ret = 0; | |
372 | + | |
373 | +fail: | |
374 | + free(bdata); | |
375 | + return ret; | |
376 | +} | |
377 | + | |
278 | 378 | static void save_env(struct fastboot_ptentry *ptn, |
279 | 379 | char *var, char *val) |
280 | 380 | { |
... | ... | @@ -470,6 +570,105 @@ |
470 | 570 | return ret; |
471 | 571 | } |
472 | 572 | |
573 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
574 | +static void process_flash_sf(const char *cmdbuf) | |
575 | +{ | |
576 | + if (download_bytes) { | |
577 | + struct fastboot_ptentry *ptn; | |
578 | + ptn = fastboot_flash_find_ptn(cmdbuf); | |
579 | + if (ptn == 0) { | |
580 | + fastboot_fail("partition does not exist"); | |
581 | + } else if ((download_bytes > ptn->length)) { | |
582 | + fastboot_fail("image too large for partition"); | |
583 | + /* TODO : Improve check for yaffs write */ | |
584 | + } else { | |
585 | + int ret; | |
586 | + char sf_command[128]; | |
587 | + /* Normal case */ | |
588 | + /* Probe device */ | |
589 | + sprintf(sf_command, "sf probe"); | |
590 | + ret = run_command(sf_command, 0); | |
591 | + if (ret){ | |
592 | + fastboot_fail("Probe sf failed"); | |
593 | + return; | |
594 | + } | |
595 | + /* Erase */ | |
596 | + sprintf(sf_command, "sf erase 0x%x 0x%x",ptn->start, /*start*/ | |
597 | + ptn->length /*size*/); | |
598 | + ret = run_command(sf_command, 0); | |
599 | + if (ret) { | |
600 | + fastboot_fail("Erasing sf failed"); | |
601 | + return; | |
602 | + } | |
603 | + /* Write image */ | |
604 | + sprintf(sf_command, "sf write 0x%x 0x%x 0x%x", | |
605 | + (unsigned int)(ulong)interface.transfer_buffer, /* source */ | |
606 | + ptn->start, /* start */ | |
607 | + download_bytes /*size*/); | |
608 | + printf("sf write '%s'\n", ptn->name); | |
609 | + ret = run_command(sf_command, 0); | |
610 | + if (ret){ | |
611 | + fastboot_fail("Writing sf failed"); | |
612 | + return; | |
613 | + } | |
614 | + printf("sf write finished '%s'\n", ptn->name); | |
615 | + fastboot_okay(""); | |
616 | + } | |
617 | + } else { | |
618 | + fastboot_fail("no image downloaded"); | |
619 | + } | |
620 | +} | |
621 | + | |
622 | +#ifdef CONFIG_ARCH_IMX8M | |
623 | +/* Check if the mcu image is built for running from TCM */ | |
624 | +static bool is_tcm_image(char *image_addr) | |
625 | +{ | |
626 | + u32 stack, pc; | |
627 | + | |
628 | + stack = *(u32 *)image_addr; | |
629 | + pc = *(u32 *)(image_addr + 4); | |
630 | + | |
631 | + if ((stack != (u32)ANDROID_MCU_FIRMWARE_HEADER_STACK) || | |
632 | + (pc != (u32)ANDROID_MCU_FIRMWARE_HEADER_PC)) { | |
633 | + printf("Please flash mcu firmware images for running from TCM\n"); | |
634 | + return false; | |
635 | + } else | |
636 | + return true; | |
637 | +} | |
638 | + | |
639 | +static int do_bootmcu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
640 | +{ | |
641 | + int ret; | |
642 | + size_t out_num_read; | |
643 | + void *m4_base_addr = (void *)M4_BOOTROM_BASE_ADDR; | |
644 | + char command[32]; | |
645 | + | |
646 | + ret = read_from_partition_multi(FASTBOOT_MCU_FIRMWARE_PARTITION, | |
647 | + 0, ANDROID_MCU_FIRMWARE_SIZE, (void *)m4_base_addr, &out_num_read); | |
648 | + if ((ret != 0) || (out_num_read != ANDROID_MCU_FIRMWARE_SIZE)) { | |
649 | + printf("Read M4 images failed!\n"); | |
650 | + return 1; | |
651 | + } else { | |
652 | + printf("run command: 'bootaux 0x%x'\n",(unsigned int)(ulong)m4_base_addr); | |
653 | + | |
654 | + sprintf(command, "bootaux 0x%x", (unsigned int)(ulong)m4_base_addr); | |
655 | + ret = run_command(command, 0); | |
656 | + if (ret) { | |
657 | + printf("run 'bootaux' command failed!\n"); | |
658 | + return 1; | |
659 | + } | |
660 | + } | |
661 | + return 0; | |
662 | +} | |
663 | + | |
664 | +U_BOOT_CMD( | |
665 | + bootmcu, 1, 0, do_bootmcu, | |
666 | + "boot mcu images\n", | |
667 | + "boot mcu images from 'm4_os' partition, only support images run from TCM" | |
668 | +); | |
669 | +#endif | |
670 | +#endif /* CONFIG_FLASH_MCUFIRMWARE_SUPPORT */ | |
671 | + | |
473 | 672 | #if defined(CONFIG_FASTBOOT_STORAGE_SATA) |
474 | 673 | static void process_flash_sata(const char *cmdbuf) |
475 | 674 | { |
... | ... | @@ -898,6 +1097,27 @@ |
898 | 1097 | |
899 | 1098 | static void rx_process_flash(const char *cmdbuf) |
900 | 1099 | { |
1100 | +/* Check if we need to flash mcu firmware */ | |
1101 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
1102 | + if (!strncmp(cmdbuf, FASTBOOT_MCU_FIRMWARE_PARTITION, | |
1103 | + sizeof(FASTBOOT_MCU_FIRMWARE_PARTITION))) { | |
1104 | + switch (fastboot_firmwareinfo.type) { | |
1105 | + case DEV_SF: | |
1106 | + process_flash_sf(cmdbuf); | |
1107 | + break; | |
1108 | +#ifdef CONFIG_ARCH_IMX8M | |
1109 | + case DEV_MMC: | |
1110 | + if (is_tcm_image(interface.transfer_buffer)) | |
1111 | + process_flash_mmc(cmdbuf); | |
1112 | + break; | |
1113 | +#endif | |
1114 | + default: | |
1115 | + printf("Don't support flash firmware\n"); | |
1116 | + } | |
1117 | + return; | |
1118 | + } | |
1119 | +#endif | |
1120 | + /* Normal case */ | |
901 | 1121 | switch (fastboot_devinfo.type) { |
902 | 1122 | #if defined(CONFIG_FASTBOOT_STORAGE_SATA) |
903 | 1123 | case DEV_SATA: |
... | ... | @@ -945,6 +1165,12 @@ |
945 | 1165 | } else { |
946 | 1166 | return 1; |
947 | 1167 | } |
1168 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
1169 | + /* For imx7ulp, flash m4 images directly to spi nor-flash, M4 will | |
1170 | + * run automatically after powered on. For imx8mq, flash m4 images to | |
1171 | + * physical partition 'm4_os', m4 will be kicked off by A core. */ | |
1172 | + fastboot_firmwareinfo.type = ANDROID_MCU_FRIMWARE_DEV_TYPE; | |
1173 | +#endif | |
948 | 1174 | |
949 | 1175 | return 0; |
950 | 1176 | } |
... | ... | @@ -1074,6 +1300,16 @@ |
1074 | 1300 | ptable[PTN_TEE_INDEX].partition_id = TEE_HWPARTITION_ID; |
1075 | 1301 | strcpy(ptable[PTN_TEE_INDEX].fstype, "raw"); |
1076 | 1302 | |
1303 | + /* Add m4_os partition if we support mcu firmware image flash */ | |
1304 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
1305 | + strcpy(ptable[PTN_M4_OS_INDEX].name, FASTBOOT_MCU_FIRMWARE_PARTITION); | |
1306 | + ptable[PTN_M4_OS_INDEX].start = ANDROID_MCU_FIRMWARE_START / dev_desc->blksz; | |
1307 | + ptable[PTN_M4_OS_INDEX].length = ANDROID_MCU_FIRMWARE_SIZE / dev_desc->blksz; | |
1308 | + ptable[PTN_M4_OS_INDEX].flags = FASTBOOT_PTENTRY_FLAGS_UNERASEABLE; | |
1309 | + ptable[PTN_M4_OS_INDEX].partition_id = user_partition; | |
1310 | + strcpy(ptable[PTN_M4_OS_INDEX].fstype, "raw"); | |
1311 | +#endif | |
1312 | + | |
1077 | 1313 | /* Bootloader */ |
1078 | 1314 | strcpy(ptable[PTN_BOOTLOADER_INDEX].name, FASTBOOT_PARTITION_BOOTLOADER); |
1079 | 1315 | ptable[PTN_BOOTLOADER_INDEX].start = |
... | ... | @@ -1097,7 +1333,7 @@ |
1097 | 1333 | if (ret) |
1098 | 1334 | break; |
1099 | 1335 | } |
1100 | - for (i = 0; i <= part_idx; i++) | |
1336 | + for (i = 0; i < tbl_idx; i++) | |
1101 | 1337 | fastboot_flash_add_ptn(&ptable[i]); |
1102 | 1338 | |
1103 | 1339 | return 0; |
include/fsl_fastboot.h
... | ... | @@ -8,6 +8,7 @@ |
8 | 8 | #ifndef FSL_FASTBOOT_H |
9 | 9 | #define FSL_FASTBOOT_H |
10 | 10 | #include <stdbool.h> |
11 | +#include <linux/types.h> | |
11 | 12 | |
12 | 13 | #define FASTBOOT_PTENTRY_FLAGS_REPEAT(n) (n & 0x0f) |
13 | 14 | #define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK 0x0000000F |
... | ... | @@ -46,6 +47,10 @@ |
46 | 47 | #define FASTBOOT_PARTITION_AVBKEY "avbkey" |
47 | 48 | #endif |
48 | 49 | |
50 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
51 | +#define FASTBOOT_MCU_FIRMWARE_PARTITION "m4_os" | |
52 | +#endif | |
53 | + | |
49 | 54 | #ifdef CONFIG_ANDROID_AB_SUPPORT |
50 | 55 | #define FASTBOOT_PARTITION_BOOT_A "boot_a" |
51 | 56 | #define FASTBOOT_PARTITION_RECOVERY "recovery" |
... | ... | @@ -81,7 +86,11 @@ |
81 | 86 | enum { |
82 | 87 | DEV_SATA, |
83 | 88 | DEV_MMC, |
84 | - DEV_NAND | |
89 | + DEV_NAND, | |
90 | +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT | |
91 | + /* SPI Flash */ | |
92 | + DEV_SF | |
93 | +#endif | |
85 | 94 | }; |
86 | 95 | |
87 | 96 | typedef enum { |
... | ... | @@ -233,5 +242,13 @@ |
233 | 242 | int check_parts_values(struct fastboot_ptentry *ptn); |
234 | 243 | #endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ |
235 | 244 | |
245 | +/* Reads |num_bytes| from offset |offset| from partition with name | |
246 | + * |partition| (NUL-terminated UTF-8 string). If |offset| is | |
247 | + * negative, its absolute value should be interpreted as the number | |
248 | + * of bytes from the end of the partition. | |
249 | + * It's basically copied from fsl_read_from_partition_multi() because | |
250 | + * we may want to read partition when AVB is not enabled. */ | |
251 | +int read_from_partition_multi(const char* partition, | |
252 | + int64_t offset, size_t num_bytes,void* buffer, size_t* out_num_read); | |
236 | 253 | #endif /* FSL_FASTBOOT_H */ |