// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_SPI_FLASH_MTD extern int spi_nor_pre(void); extern int spi_nor_probe(u32 init_flag); #endif #ifdef CONFIG_SPI_NAND extern int spi_nand_pre(void); extern int spi_nand_probe(u32 init_flag); #endif #ifdef CONFIG_MTD_SPI_NAND extern int spi_nand_pre(void); extern int spi_nand_probe(u32 init_flag); #endif #ifdef CONFIG_AML_NAND extern int amlnf_pre(void); extern int amlnf_probe(u32 init_flag); #endif #ifdef CONFIG_MESON_NFC extern int nand_pre(void); extern int nand_probe(uint32_t init_flag); #endif #ifdef CONFIG_MMC_MESON_GX extern int emmc_pre(void); extern int emmc_probe(u32 init_flag); #endif #ifdef CONFIG_MMC_MESON_GX extern int sdcard_pre(void); extern int sdcard_probe(u32 init_flag); #endif /* for info protect, fixme later */ int info_disprotect = 0; static struct storage_t *current; static struct device_node_t device_list[] = { #ifdef CONFIG_MESON_NFC {BOOT_NAND_MTD, "mtd", nand_pre, nand_probe}, #endif #ifdef CONFIG_AML_NAND {BOOT_NAND_NFTL, "nftl", amlnf_pre, amlnf_probe}, #endif #ifdef CONFIG_SPI_NAND /* old drivers will be removed later */ {BOOT_SNAND, "spi-nand", spi_nand_pre, spi_nand_probe}, #endif #ifdef CONFIG_MTD_SPI_NAND {BOOT_SNAND, "spi-nand", spi_nand_pre, spi_nand_probe}, #endif #ifdef CONFIG_SPI_FLASH_MTD {BOOT_SNOR, "spi-nor", spi_nor_pre, spi_nor_probe}, #endif #if 0 {BOOT_SD, "sd", sdcard_pre, sdcard_probe}, #endif #ifdef CONFIG_MMC_MESON_GX {BOOT_EMMC, "emmc", emmc_pre, emmc_probe}, #endif }; int store_register(struct storage_t *store_dev) { if (!store_dev) return 1; if (!current) { INIT_LIST_HEAD(&store_dev->list); current = store_dev; return 0; } /** * the head node will not be a valid node * usually when we use the list, but in storage * interface module, we init the device node as * a head instead a global list_head pointer, * it should be traver scaled. */ if (store_dev == current) return 0; struct storage_t *dev; if (store_dev->type == current->type) return 1; list_for_each_entry(dev, ¤t->list, list) { if (dev == store_dev) return 0; else if (dev->type == store_dev->type) return 1; } list_add_tail(&store_dev->list, ¤t->list); current = store_dev; return 0; } void store_unregister(struct storage_t *store_dev) { if (store_dev == current) { if (list_empty_careful(&store_dev->list)) { current = NULL; } else { current = list_entry((current->list).next, struct storage_t, list); list_del_init(&store_dev->list); } } else { list_del_init(&store_dev->list); } } int sheader_need(void) { return BOOTLOADER_MODE_ADVANCE_INIT; } unsigned char *ubootdata = NULL; void sheader_load(void *addr) { ubootdata = addr; } /* * storage header which size is 512B * is bind into the tail of bl2.bin. * @addr: uboot address. */ static p_payload_info_t parse_uboot_sheader(void *addr) { p_payload_info_t pInfo = (p_payload_info_t)(addr + BL2_SIZE); if (AML_MAGIC_HDR_L == pInfo->hdr.nMagicL && AML_MAGIC_HDR_R == pInfo->hdr.nMagicR) { printf("aml log : bootloader blxx mode!\n"); return pInfo; } return NULL; } boot_area_entry_t general_boot_part_entry[MAX_BOOT_AREA_ENTRIES] = { {BOOT_BL2, BOOT_AREA_BB1ST, 0, 0}, {BOOT_BL2E, BOOT_AREA_BL2E, 0, 0}, {BOOT_BL2X, BOOT_AREA_BL2X, 0, 0}, {BOOT_DDRFIP, BOOT_AREA_DDRFIP, 0, 0}, {BOOT_DEVFIP, BOOT_AREA_DEVFIP, 0, 0}, }; struct boot_layout general_boot_layout = {.boot_entry = general_boot_part_entry}; struct storage_startup_parameter g_ssp; struct storage_bl *g_storage = NULL; static void storage_boot_layout_debug_info( struct boot_layout *boot_layout) { boot_area_entry_t *boot_entry = boot_layout->boot_entry; int i; printf("boot area list: \n"); for (i = 0; i <= BOOT_AREA_DEVFIP; i++) { printf("%10s ", boot_entry[i].name); printf("%10llx ", boot_entry[i].offset); printf("%10llx\n", boot_entry[i].size); } } /* use STORAGE_ROUND_UP, y must be power of 2 */ #define STORAGE_ROUND_UP_IF_UNALIGN(x, y) ((x) = (((x) + (y) - 1) & (~(y - 1)))) #define ALIGN_SIZE (4096) static int storage_boot_layout_rebuild(struct boot_layout *boot_layout) { struct storage_startup_parameter *ssp = &g_ssp; boot_area_entry_t *boot_entry = boot_layout->boot_entry; uint64_t align_size, cal_copy = 1; cpu_id_t cpu_id = get_cpu_id(); uint8_t i = BOOT_AREA_BL2E; align_size = ALIGN_SIZE; STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BB1ST].size, align_size); STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BL2E].size, align_size); STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BL2X].size, align_size); if (ssp->boot_device == BOOT_SNAND || ssp->boot_device == BOOT_NAND_MTD) { if (ssp->boot_device == BOOT_SNAND) { #ifdef CONFIG_SPINAND_BL2_COPY_NUM STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BB1ST].size, ((BOOT_TOTAL_PAGES / CONFIG_SPINAND_BL2_COPY_NUM) * ssp->sip.nsp.page_size)); #else STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BB1ST].size, ((BOOT_TOTAL_PAGES / ssp->boot_backups) * ssp->sip.nsp.page_size)); #endif } else { STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BB1ST].size, ((BOOT_TOTAL_PAGES / ssp->boot_backups) * ssp->sip.nsp.page_size)); } boot_entry[BOOT_AREA_BL2E].offset = NAND_RSV_OFFSET * ssp->sip.nsp.page_size + ssp->sip.nsp.layout_reserve_size; ssp->boot_entry[BOOT_AREA_BL2E].offset = boot_entry[BOOT_AREA_BL2E].offset; if (store_boot_layout_is_discrete_all()) { align_size = ssp->sip.nsp.block_size; cal_copy = ssp->boot_backups; STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_BL2E].size, align_size); } i = BOOT_AREA_BL2X; } else if (ssp->boot_device == BOOT_EMMC) { ssp->boot_entry[BOOT_AREA_BB1ST].offset = boot_entry[BOOT_AREA_BB1ST].offset += BL2_CORE_BASE_OFFSET_EMMC; } else if (ssp->boot_device == BOOT_SNOR && cpu_id.family_id == MESON_CPU_MAJOR_ID_A4) { ssp->boot_entry[BOOT_AREA_BB1ST].offset = boot_entry[BOOT_AREA_BB1ST].offset += 0x200; } ssp->boot_entry[BOOT_AREA_BB1ST].size = boot_entry[BOOT_AREA_BB1ST].size; ssp->boot_entry[BOOT_AREA_BL2E].size = boot_entry[BOOT_AREA_BL2E].size; for (; i <= BOOT_AREA_DEVFIP; i++) { STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[i].size, align_size); boot_entry[i].offset = boot_entry[i - 1].offset + boot_entry[i - 1].size * cal_copy; ssp->boot_entry[i].size = boot_entry[i].size; ssp->boot_entry[i].offset = boot_entry[i].offset; } return 0; } /* use STORAGE_ROUND_UP, y must be power of 2 */ #define STORAGE_ROUND_UP_IF_UNALIGN(x, y) ((x) = (((x) + (y) - 1) & (~(y - 1)))) #define ALIGN_SIZE (4096) static int storage_boot_layout_general_setting(struct boot_layout *boot_layout, int need_build) { struct storage_startup_parameter *ssp = &g_ssp; boot_area_entry_t *boot_entry = boot_layout->boot_entry; struct storage_boot_entry *sbentry = ssp->boot_entry; p_payload_info_t pInfo = parse_uboot_sheader(ubootdata); p_payload_info_hdr_t hdr; p_payload_info_item_t pItem; int offPayload = 0, szPayload = 0; unsigned int bl2e_size = 0, bl2x_size = 0; char name[8] = {0}; int nIndex = 0; if (need_build == BOOT_ID_USB) { if (!pInfo) return -1; hdr = &pInfo->hdr; pItem = pInfo->arrItems; for (nIndex = 1, pItem += 1; nIndex < hdr->byItemNum; ++nIndex, ++pItem) { memcpy(name, &pItem->nMagic, sizeof(unsigned int)); offPayload = pItem->nOffset; if (nIndex == BOOT_AREA_BL2E) bl2e_size = pItem->nPayLoadSize; if (nIndex == BOOT_AREA_BL2X) bl2x_size = pItem->nPayLoadSize; szPayload = pItem->nPayLoadSize; pr_info("Item[%d]%4s offset 0x%08x sz 0x%x\n", nIndex, name, offPayload, szPayload); } boot_entry[BOOT_AREA_BB1ST].size = ssp->boot_entry[BOOT_AREA_BB1ST].size; boot_entry[BOOT_AREA_BL2E].size = bl2e_size; boot_entry[BOOT_AREA_BL2X].size = bl2x_size; boot_entry[BOOT_AREA_DDRFIP].size = ssp->boot_entry[BOOT_AREA_DDRFIP].size; boot_entry[BOOT_AREA_DEVFIP].size = ssp->boot_entry[BOOT_AREA_DEVFIP].size; storage_boot_layout_rebuild(boot_layout); } else { /* may be sdcard boot and also have to rebuild layout */ if (need_build == BOOT_ID_SDCARD) { bl2e_size = sbentry[BOOT_AREA_BL2E].size; bl2x_size = sbentry[BOOT_AREA_BL2X].size; printf("bl2e_size=%x bl2x_size=%x current->type=%d\n", bl2e_size, bl2x_size, current->type); boot_entry[BOOT_AREA_BB1ST].size = ssp->boot_entry[BOOT_AREA_BB1ST].size; boot_entry[BOOT_AREA_BL2E].size = bl2e_size; boot_entry[BOOT_AREA_BL2X].size = bl2x_size; boot_entry[BOOT_AREA_DDRFIP].size = ssp->boot_entry[BOOT_AREA_DDRFIP].size; boot_entry[BOOT_AREA_DEVFIP].size = ssp->boot_entry[BOOT_AREA_DEVFIP].size; storage_boot_layout_rebuild(boot_layout); goto out; } /* normal boot */ for (nIndex = 0; nIndex <= BOOT_AREA_DEVFIP; nIndex++, sbentry++) { boot_entry[nIndex].size = sbentry->size; boot_entry[nIndex].offset = sbentry->offset; } } out: /* devfip size (BOARD_DEVFIP_SIZE) maybe not align block size, * so we need to resize. */ if (store_boot_layout_is_discrete_bl2()) { STORAGE_ROUND_UP_IF_UNALIGN(boot_entry[BOOT_AREA_DEVFIP].size, current->info.erase_unit); ssp->boot_entry[BOOT_AREA_DEVFIP].size = boot_entry[BOOT_AREA_DEVFIP].size; } return 0; } uint8_t emmc_boot_seqs_tbl[8][2] = { {0, 3}, {0, 2}, {0, 3}, {0, 1}, {1, 2}, {1, 1}, {2, 1}, {0, 0} }; static int _get_emmc_boot_seqs(void) { uint8_t ebcfg = 0; if (IS_FEAT_DIS_EMMC_USER()) ebcfg |= (1<<2); if (IS_FEAT_DIS_EMMC_BOOT_0()) ebcfg |= (1<<1); if (IS_FEAT_DIS_EMMC_BOOT_1()) ebcfg |= (1<<0); return ebcfg; } static int storage_get_emmc_boot_seqs(void) { return emmc_boot_seqs_tbl[_get_emmc_boot_seqs()][1];; } static int storage_get_emmc_boot_start(void) { return emmc_boot_seqs_tbl[_get_emmc_boot_seqs()][0];; } #define NSP_PAGE0_DISABLE 1 extern unsigned char *ubootdata; static int storage_get_and_parse_ssp(int *need_build) // boot_device: { struct storage_startup_parameter *ssp = &g_ssp; union storage_independent_parameter *sip; static struct param_e *storage_param_e; int usb_boot = *need_build; memset(ssp, 0, sizeof(struct storage_startup_parameter)); if (!usb_boot) { storage_param_e = param_of(STORAGE_PARAM_TYPE); if (!storage_param_e) return -1; memcpy(ssp, storage_param_e->data, sizeof(struct storage_startup_parameter)); /* may be sdcard boot and also have to rebuild layout */ if (ssp->boot_device == BOOT_ID_SDCARD || ssp->boot_device == BOOT_ID_USB) { /* need change the storage base here */ *need_build = ssp->boot_device; } } if (*need_build) { sip = &ssp->sip; ssp->boot_device = current->type; switch (ssp->boot_device) { case BOOT_EMMC: ssp->boot_backups = storage_get_emmc_boot_seqs(); ssp->boot_layout = BOOT_DISCRETE_DEFAULT; break; case BOOT_SNOR: ssp->boot_layout = BOOT_DISCRETE_ALL; if (IS_FEAT_EN_4BL2_SNOR()) ssp->boot_backups = 4; else if (IS_FEAT_DIS_NBL2_SNOR()) ssp->boot_backups = 1; else ssp->boot_backups = 1; break; case BOOT_SNAND: case BOOT_NAND_MTD: #ifdef BOARD_BL2EX_BACKUPS ssp->boot_backups = BOARD_BL2EX_BACKUPS; #else if (ssp->boot_device == BOOT_SNAND) { if (IS_FEAT_EN_8BL2_SNAND()) ssp->boot_backups = 8; else if (IS_FEAT_DIS_NBL2_SNAND()) ssp->boot_backups = 1; else /* Default 4 backup, consistent with rom */ ssp->boot_backups = 4; } else { ssp->boot_backups = 8; if (IS_FEAT_DIS_8BL2_NAND()) ssp->boot_backups = 4; else if (IS_FEAT_DIS_NBL2_NAND()) ssp->boot_backups = 1; } #endif #ifdef BOARD_BOOT_LAYOUT_DISCRETE_BL2 ssp->boot_layout = BOOT_DISCRETE_BL2; #else ssp->boot_layout = BOOT_DISCRETE_ALL; #endif sip->nsp.page_size = current->info.write_unit; sip->nsp.block_size = current->info.erase_unit; sip->nsp.pages_per_block = current->info.erase_unit / current->info.write_unit; sip->nsp.layout_reserve_size = NAND_RSV_BLOCK_NUM * sip->nsp.block_size; sip->nsp.page0_disable = NSP_PAGE0_DISABLE; break; default: /* do nothing. */ break; } sip->nsp.boot_layout_compat = ssp->boot_layout; } /* sanity check */ printf("boot_device:%d\n", ssp->boot_device); printf("boot_seq:%d\n", ssp->boot_seq); printf("boot_backups:%d\n", ssp->boot_backups); printf("boot_layout :%d\n", ssp->boot_layout); printf("boot_layout_compat :%d\n", ssp->sip.nsp.boot_layout_compat); printf("rebuild_id :%d\n", *need_build); return 0; } int storage_post_init(void) { int ret = -1; int need_build = 0; ret = storage_get_and_parse_ssp(&need_build); if (ret < 0) return -1; ret = storage_boot_layout_general_setting(&general_boot_layout, need_build); if (ret < 0) return ret; storage_boot_layout_debug_info(&general_boot_layout); return ret; } int store_init(u32 init_flag) { int i, ret = 0; u8 record = 0; /*1. pre scan*/ for (i = 0; i < ARRAY_SIZE(device_list); i++) { if (!device_list[i].pre()) { record |= BIT(i); } } pr_info("record = 0x%x\n", record); if (!record) { pr_info("No Valid storage device\n"); return record; } if (BOOTLOADER_MODE_ADVANCE_INIT) storage_post_init(); /*2. Enter the probe of the valid device*/ for (i = 0; i < ARRAY_SIZE(device_list); i++) { if (record & BIT(i)) { ret = device_list[i].probe(init_flag); if (ret) pr_info("the 0x%x storage device probe failed\n", device_list[i].index); } } return record; } struct storage_t *store_get_current(void) { return current; } int store_set_device(enum boot_type_e type) { struct list_head *entry; struct storage_t *dev, *store_dev = store_get_current(); if (!store_dev) { pr_info("%s %d no current device\n", __func__, __LINE__); return 1; } if (store_dev->type == type) return 0; list_for_each(entry, &store_dev->list) { dev = list_entry(entry, struct storage_t, list); if (dev->type == type) { current = dev; return 0; } } pr_info("%s %d please confirm the %d device is valid\n", __func__, __LINE__, type); return 1; } enum boot_type_e store_get_type(void) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return BOOT_NONE; } return store->type; } int store_get_device_info(struct storage_info_t *info) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } memcpy((char *)info, (char *)&store->info, sizeof(struct storage_info_t)); return 0; } int store_get_device_bootloader_mode(void) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return -1; } return store->info.mode; } int store_read(const char *name, loff_t off, size_t size, void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->read(name, off, size, buf); } int store_write(const char *name, loff_t off, size_t size, void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->write(name, off, size, buf); } int store_erase(const char *name, loff_t off, size_t size, int scrub) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->erase(name, off, size, scrub); } u64 store_part_size(const char *name) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->get_part_size(name); } u8 store_boot_copy_num(const char *name) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->get_copies(name); } #ifndef SYSCTRL_SEC_STATUS_REG2 static u32 fake_reg = 0; #define SYSCTRL_SEC_STATUS_REG2 (&fake_reg) #endif u8 store_boot_copy_start(void) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 0; } if (store->type != BOOT_EMMC) return 0; /* new arch since sc2 */ if (BOOTLOADER_MODE_ADVANCE_INIT) return storage_get_emmc_boot_start(); return 0; } u8 store_bootup_bootidx(const char *name) { u8 bl2_idx = 0, fip_idx = 0; u32 val = 0; /* new arch since sc2 */ if (BOOTLOADER_MODE_ADVANCE_INIT) { bl2_idx = readl(SYSCTRL_SEC_STATUS_REG2) & 0xF; //TODO: fixme after robust devfip is finished. fip_idx = bl2_idx; } else { /* accroding to the: commit 975b4acbcfa686601999d56843471d98e9c0a2cd storage: robust boot: record bootlog in SEC_AO_SEC_GP_CFG2 [1/2] PD#SWPL-4850 ... record the bootup bl2/fip into SEC_AO_SEC_GP_CFG2 bit[27-25] bl2 bit[24-22] fip */ val = readl(SEC_AO_SEC_GP_CFG2); bl2_idx = (val >> 25) & 0x7; fip_idx = (val >> 22) & 0x7; } if (!strncmp(name, "bl2", sizeof("bl2")) || !strncmp(name, "spl", sizeof("spl"))) return bl2_idx; else return fip_idx; } void store_restore_bootidx(void) { /* new arch since sc2 */ if (BOOTLOADER_MODE_ADVANCE_INIT) { extern void aml_set_bootsequence(uint32_t val); aml_set_bootsequence(0x55); } return; } u64 store_boot_copy_size(const char *name) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->get_copy_size(name); } int store_send_param(void) { struct storage_t *store = store_get_current(); if (!store || !store->param_ops) { pr_info("%s %d please init storage func first\n", __func__, __LINE__); return 1; } return store->param_ops(); } static int _store_boot_read(const char *part_name, u8 cpy, size_t size, void *addr) { struct storage_t *store = store_get_current(); int ret, read_len, tpl_offset = BL2_SIZE; if (store_get_device_bootloader_mode() == COMPACT_BOOTLOADER) return store->boot_read(part_name, cpy, size, (u_char *)addr); read_len = size > tpl_offset ? tpl_offset : size; ret = store->boot_read(BOOT_BL2, cpy, read_len, addr); if (ret) { pr_err("read bl2 fail\n"); goto out; } if (size <= BL2_SIZE) goto out; if (store_boot_layout_is_discrete_all()) { p_payload_info_t pinfo = parse_uboot_sheader((u8 *)ubootdata); p_payload_info_hdr_t hdr = &pinfo->hdr; p_payload_info_item_t pitem = pinfo->arrItems; int nindex, offset = 0; tpl_offset = ALIGN(BL2_SIZE, ALIGN_SIZE); for (nindex = 1, pitem += 1; nindex < hdr->byItemNum; ++nindex, ++pitem) { pr_info("item[%d]%4s offset 0x%08x sz 0x%x\n", nindex, (char *)&pitem->nMagic, offset, pitem->nPayLoadSize); if (!pitem->nPayLoadSize) continue; read_len = size > pitem->nPayLoadSize ? pitem->nPayLoadSize : size; if (read_len > 0) { ret = store->boot_read(general_boot_part_entry[nindex].name, cpy, read_len, (u_char *)(addr + tpl_offset + offset)); if (ret) { pr_info("Fail in flash payload %s\n", general_boot_part_entry[nindex].name); goto out; } } offset += pitem->nPayLoadSize; size -= read_len; } } else { if (store_boot_layout_is_discrete_bl2()) tpl_offset = ALIGN(BL2_SIZE, ALIGN_SIZE); ret = store->boot_read(BOOT_TPL, cpy, size - tpl_offset, (u_char *)addr + tpl_offset); if (ret) { pr_err("read tpl fail\n"); goto out; } } out: return ret; } int store_boot_read(const char *name, u8 copy, size_t size, void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } if (strcmp(name, "bootloader") == 0) return _store_boot_read(name, copy, size, buf); return store->boot_read(name, copy, size, buf); } static int bl2x_mode_check_header(p_payload_info_t pInfo) { p_payload_info_hdr_t hdr = &pInfo->hdr; const int nItemNum = hdr->byItemNum; p_payload_info_item_t pItem = pInfo->arrItems; u8 i = 0; int sz_payload = 0; uint64_t align_size = 1; struct storage_startup_parameter *ssp = &g_ssp; uint64_t cal_copy = ssp->boot_backups; printf("\naml log : info parse...\n"); printf("\tsztimes : %s\n", hdr->szTimeStamp); printf("\tversion : %d\n", hdr->byVersion); printf("\tItemNum : %d\n", nItemNum); printf("\tSize : %d(0x%x)\n", hdr->nSize, hdr->nSize); if (nItemNum > MAX_BOOT_AREA_ENTRIES || nItemNum < 3) { pr_info("illegal nitem num %d\n", nItemNum); return __LINE__; } if (ssp->boot_device == BOOT_NAND_MTD || ssp->boot_device == BOOT_SNAND) align_size = ((NAND_RSV_OFFSET / cal_copy) * ssp->sip.nsp.page_size); sz_payload = pItem->nPayLoadSize; STORAGE_ROUND_UP_IF_UNALIGN(sz_payload, align_size); if (sz_payload > ssp->boot_entry[0].size) return __LINE__; if (ssp->boot_device == BOOT_NAND_MTD || ssp->boot_device == BOOT_SNAND) align_size = ssp->sip.nsp.block_size; ++pItem; for (i = 1; i < nItemNum; i++, ++pItem) { sz_payload = pItem->nPayLoadSize; STORAGE_ROUND_UP_IF_UNALIGN(sz_payload, align_size); if (sz_payload > ssp->boot_entry[i].size) return __LINE__; } return 0; } static int _store_boot_write(const char *part_name, u8 cpy, size_t size, void *addr) { enum boot_type_e medium_type = store_get_type(); struct storage_startup_parameter *ssp = &g_ssp; int ret = 0; struct storage_t *store = store_get_current(); int bl2_size = BL2_SIZE; int bl2_cpynum = 0; int tpl_per_size = CONFIG_TPL_SIZE_PER_COPY; int tpl_cpynum = 0; int bootloader_maxsize = 0; if (store_get_device_bootloader_mode() == COMPACT_BOOTLOADER) return store->boot_write(part_name, cpy, size, (u_char *)addr); if (BOOT_NAND_MTD == medium_type || BOOT_SNAND == medium_type) tpl_cpynum = CONFIG_NAND_TPL_COPY_NUM; else if (medium_type == BOOT_SNOR) tpl_cpynum = CONFIG_NOR_TPL_COPY_NUM; if (store_get_device_bootloader_mode() == ADVANCE_BOOTLOADER) { bl2_cpynum = ssp->boot_backups; } else { bootloader_maxsize = bl2_size + tpl_per_size; bl2_cpynum = CONFIG_BL2_COPY_NUM; if (size > bootloader_maxsize) { pr_info("bootloader sz 0x%lx too large,max sz 0x%x\n", size, bootloader_maxsize); return CMD_RET_FAILURE; } } if ((cpy >= tpl_cpynum || cpy >= bl2_cpynum) && cpy != BOOT_OPS_ALL) { pr_info("update copy %d invalid, must < min(%d, %d)\n", cpy, tpl_cpynum, bl2_cpynum); return CMD_RET_FAILURE; } if (store_boot_layout_is_discrete_all()) { p_payload_info_t pinfo = parse_uboot_sheader((u8 *)addr); p_payload_info_hdr_t hdr = &pinfo->hdr; p_payload_info_item_t pitem = pinfo->arrItems; char name[8]; int nindex = 0, off_payload = 0, sz_payload = 0; if (bl2x_mode_check_header(pinfo)) { pr_info("!!!warning bl2xx size is bigger than bl2x layout size\n"); pr_info("please check bl2x,or erase flash and turn off\n"); pr_info("then turn on, and update uboot again\n"); return CMD_RET_FAILURE; } memset(name, 0, 8); for (nindex = 1, pitem += 1; nindex < hdr->byItemNum; ++nindex, ++pitem) { memcpy(name, &pitem->nMagic, sizeof(unsigned int)); off_payload = pitem->nOffset; sz_payload = pitem->nPayLoadSize; pr_info("item[%d]%4s offset 0x%08x sz 0x%x\n", nindex, name, off_payload, sz_payload); if (!sz_payload) continue; ret = store->boot_write(general_boot_part_entry[nindex].name, cpy, sz_payload, (u_char *)(addr + off_payload)); if (ret) { pr_info("Fail in flash payload %s\n", name); return CMD_RET_FAILURE; } } } else if (store_boot_layout_is_discrete_bl2()) { ret = store->boot_write("tpl", cpy, size - ALIGN(bl2_size, ALIGN_SIZE), (u_char *)(addr + ALIGN(bl2_size, ALIGN_SIZE))); } else { ret = store->boot_write("tpl", cpy, size - bl2_size, (u_char *)(addr + bl2_size)); if (ret) { pr_info("failed update tpl\n"); return CMD_RET_FAILURE; } } ret = store->boot_write("bl2", cpy, bl2_size, (u_char *)addr); if (ret) { pr_info("Fail in flash payload bl2\n"); return CMD_RET_FAILURE; } return ret; } int store_boot_write(const char *name, u8 copy, size_t size, void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } if (strcmp(name, "bootloader") == 0) return _store_boot_write(name, copy, size, buf); return store->boot_write(name, copy, size, buf); } int store_boot_erase(const char *name, u8 copy) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->boot_erase(name, copy); } int store_gpt_read(void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } if (!store->gpt_read) return 1; return store->gpt_read(buf); } int store_gpt_write(void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } if (!store->gpt_write) return 1; return store->gpt_write(buf); } int store_gpt_erase(void) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } if (!store->gpt_erase) return 1; return store->gpt_erase(); } int store_boot_copy_enable(int index) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return -1; } if (!store->boot_copy_enable) return -1; return store->boot_copy_enable(index); } u32 store_rsv_size(const char *name) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->get_rsv_size(name); } int store_rsv_read(const char *name, size_t size, void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->read_rsv(name, size, buf); } int store_rsv_write(const char *name, size_t size, void *buf) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->write_rsv(name, size, buf); } int store_rsv_erase(const char *name) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->erase_rsv(name); } int store_rsv_protect(const char *name, bool ops) { struct storage_t *store = store_get_current(); if (!store) { pr_info("%s %d please init storage device first\n", __func__, __LINE__); return 1; } return store->protect_rsv(name, ops); } static int do_store_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u32 init_flag = 1; u8 ret = 0; if (unlikely(argc != 2 && argc != 3)) return CMD_RET_USAGE; if (argc == 3) init_flag = simple_strtoul(argv[2], NULL, 10); /*Returns a nonzero value: device index*/ if (store_init(init_flag)) ret = 0; else ret = 1; return ret; } void store_print_device(struct storage_t *store_dev) { int i; for (i = 0; i < ARRAY_SIZE(device_list); i++) if (store_dev->type & device_list[i].index) pr_info("device type: [%s]\n", device_list[i].type); pr_info("name %s\n", store_dev->info.name); pr_info("id :"); for (i = 0; i < ARRAY_SIZE(store_dev->info.id); i++) pr_info(" 0x%x", store_dev->info.id[i]); pr_info("\n"); pr_info("read unit %d\n", store_dev->info.read_unit); pr_info("write unit %d\n", store_dev->info.write_unit); pr_info("erase unit %d\n", store_dev->info.erase_unit); pr_info("total size %lld\n", store_dev->info.caps); if (store_dev->info.mode) pr_info("bootloader in discrete mode : %d\n", store_dev->info.mode); else pr_info("bootloader in compact mode : %d\n", store_dev->info.mode); } static int do_store_device(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc == 2) { struct storage_t *store_dev, *dev; struct list_head *entry; store_dev = store_get_current(); pr_info("current device:\n"); pr_info("----------------------------------\n"); store_print_device(store_dev); pr_info("----------------------------------\n"); list_for_each(entry, &store_dev->list) { dev = list_entry(entry, struct storage_t, list); pr_info("valid device:\n"); pr_info("----------------------------------\n"); store_print_device(dev); pr_info("----------------------------------\n"); } return 0; } else if (argc == 3) { char *name = NULL; int i = 0, ret = 0; name = argv[2]; for (i = 0; i < ARRAY_SIZE(device_list); i++) if (!strcmp(name, device_list[i].type)) { ret = store_set_device(device_list[i].index); if (!ret) { pr_info("now current device is: %s\n", name); return 0; } } pr_info("%s %d no such device: %s\n", __func__, __LINE__, name); return ret; } return CMD_RET_USAGE; } static int do_store_partition(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store_dev; int i = 0, partitions = 0; int ret = 0; char name[16]; if (argc > 2) return CMD_RET_USAGE; else { store_dev = store_get_current(); if (store_dev->get_part_count) partitions = store_dev->get_part_count(); pr_info("%d partitions of device %s:\n", partitions, store_dev->info.name); if (store_dev->list_part_name) ret = store_dev->list_part_name(i, name); return ret; } } #ifdef CONFIG_AML_MTD extern int is_mtd_store_boot_area(const char *part_name); #endif static int do_store_erase(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long offset; size_t size = 0; char *name = NULL; char *s; int erase_flag = 0, ret; unsigned long time; const char *scrub = "Warning: scrub_flag is 1!!!!" "scrub operation!!!\n" "will erase oob area\n" "There is no reliable way to recover them.\n" " " "are sure of what you are doing!\n" "\nReally erase this NAND flash? \n"; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (!strncmp(argv[1], "scrub", 5)) { erase_flag |= STORE_SCRUB; puts(scrub); if (!confirm_yesno()) { printf("erase aborted\n"); return 1; } } /*store erase.chip*/ s = strchr(argv[1], '.'); if (s != NULL && strcmp(s, ".chip") == 0) { if (argc == 3 && !simple_strtoul(argv[argc - 1], NULL, 16)) erase_flag |= STORE_ERASE_DATA; else if ((argc == 3) && (simple_strtoul(argv[argc - 1], NULL, 16) == 1)) erase_flag |= STORE_ERASE_RSV; else if (argc == 3) return CMD_RET_USAGE; offset = 0; } else { /*store erase normal, partition name can't NULL*/ if (unlikely(argc != 5)) return CMD_RET_USAGE; size = (size_t)simple_strtoul(argv[argc - 1], NULL, 16); offset = simple_strtoul(argv[argc - 2], NULL, 16); name = argv[2]; #ifdef CONFIG_AML_MTD if (is_mtd_store_boot_area(name)) { pr_info("%s %d please enter normal partition name except tpl area!\n", __func__, __LINE__); return CMD_RET_FAILURE; } #endif } time = get_timer(0); ret = store->erase(name, offset, size, erase_flag); time = get_timer(time); if (size != 0) printf("%lu bytes ", size); printf("erased in %lu ms", time); if ((time > 0) && (size != 0)) { puts(" ("); print_size(div_u64(size, time) * 1000, "/s"); puts(")"); } puts("\n"); return ret; } static int do_store_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long offset, addr, time; size_t size; char *name = NULL; int ret; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 5 && argc != 6)) return CMD_RET_USAGE; addr = simple_strtoul(argv[2], NULL, 16); size = (size_t)simple_strtoul(argv[argc - 1], NULL, 16); offset = simple_strtoul(argv[argc - 2], NULL, 16); if (argc == 6) name = argv[3]; #ifdef CONFIG_AML_MTD if (is_mtd_store_boot_area(name)) { pr_info("%s %d please enter normal partition name except tpl area!\n", __func__, __LINE__); return CMD_RET_FAILURE; } #endif time = get_timer(0); ret = store->read(name, offset, size, (u_char *)addr); time = get_timer(time); if (size != 0) pr_info("%lu bytes ", size); pr_info("read in %lu ms", time); if ((time > 0) && (size != 0)) { puts(" ("); print_size(div_u64(size, time) * 1000, "/s"); puts(")"); } puts("\n"); return ret; } static int name2index(struct boot_layout *boot_layout, const char *img) { boot_area_entry_t *boot_entry = NULL; int i; boot_entry = boot_layout->boot_entry; for (i = 1; i <= BOOT_AREA_DEVFIP; i++) { if (!strncmp(img, boot_entry[i].name, strlen(boot_entry[i].name))) return i; } return -1; } static int do_store_write_bl2img(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long offset, addr; size_t size, size_src; char *name = NULL; int ret = -1, index; struct boot_layout *boot_layout = &general_boot_layout; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } addr = simple_strtoul(argv[2], NULL, 16); name = argv[3]; size = simple_strtoul(argv[4], NULL, 16); index = name2index(&general_boot_layout, name); offset = boot_layout->boot_entry[index].offset; size_src = boot_layout->boot_entry[index].size; printf("[%s] offset:0x%lx, index:%d\n", name, offset, index); if (size_src != size) printf("new img size:0x%lx != img src:0x%lx\n", size, size_src); ret = store->boot_write(name, offset, size, (u_char *)addr); return ret; } int store_write_bl2img(void* addr, const char *name, size_t size) { struct storage_t *store = store_get_current(); unsigned long offset; size_t size_src; int ret = -1, index; struct boot_layout *boot_layout = &general_boot_layout; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } index = name2index(&general_boot_layout, name); offset = boot_layout->boot_entry[index].offset; size_src = boot_layout->boot_entry[index].size; printf("[%s] offset:0x%lx, index:%d\n", name, offset, index); if (size_src != size) printf("new img size:0x%zx != img src:0x%zx\n", size, size_src); ret = store->boot_write(name, offset, size, (u_char *)addr); if (size != 0) printf("[%s][%d]%lx bytes\n", __func__, __LINE__, size); return ret; } static int do_store_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long offset, addr, time; size_t size; char *name = NULL; int ret; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 5 && argc != 6)) return CMD_RET_USAGE; addr = simple_strtoul(argv[2], NULL, 16); offset = simple_strtoul(argv[argc - 2], NULL, 16); size = (size_t)simple_strtoul(argv[argc - 1], NULL, 16); if (argc == 6) name = argv[3]; #ifdef CONFIG_AML_MTD if (is_mtd_store_boot_area(name)) { pr_info("%s %d please enter normal partition name except tpl area!\n", __func__, __LINE__); return CMD_RET_FAILURE; } #endif time = get_timer(0); ret = store->write(name, offset, size, (u_char *)addr); time = get_timer(time); if (size != 0) printf("%lu bytes ", size); printf("write in %lu ms", time); if ((time > 0) && (size != 0)) { puts(" ("); print_size(div_u64(size, time) * 1000, "/s"); puts(")"); } puts("\n"); return ret; } static int do_store_boot_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long addr; size_t size; u8 cpy; char *name; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 6)) return CMD_RET_USAGE; name = argv[2]; addr = (unsigned long)simple_strtoul(argv[3], NULL, 16); cpy = (u8)simple_strtoul(argv[4], NULL, 16); size = (size_t)simple_strtoul(argv[5], NULL, 16); return store->boot_read(name, cpy, size, (u_char *)addr); } static int do_store_boot_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long addr; size_t size; u8 cpy = BOOT_OPS_ALL; char *name; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 5 && argc != 6)) return CMD_RET_USAGE; name = argv[2]; addr = (unsigned long)simple_strtoul(argv[3], NULL, 16); size = (size_t)simple_strtoul(argv[argc - 1], NULL, 16); if (argc == 6) cpy = (u8)simple_strtoul(argv[4], NULL, 16); if (strcmp(name, "bootloader") == 0) { return _store_boot_write(name, cpy, size, (u_char *)addr); } return store->boot_write(name, cpy, size, (u_char *)addr); } static int do_store_boot_erase(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); u8 cpy = BOOT_OPS_ALL; char *name; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 3 && argc != 4)) return CMD_RET_USAGE; name = argv[2]; if (argc == 4) cpy = (u8)simple_strtoul(argv[3], NULL, 16); return store->boot_erase(name, cpy); } static int do_store_gpt_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long addr; int ret; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 3)) return CMD_RET_USAGE; addr = simple_strtoul(argv[2], NULL, 16); if (store->gpt_read) { ret = store->gpt_read((u_char *)addr); return ret; } printf("read gpt is not prepared\n"); return CMD_RET_USAGE; } static int do_store_gpt_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); unsigned long addr; int ret; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 3)) return CMD_RET_USAGE; addr = simple_strtoul(argv[2], NULL, 16); if (store->gpt_write) { ret = store->gpt_write((u_char *)addr); return ret; } printf("write gpt is not prepared\n"); return CMD_RET_USAGE; } static int do_store_gpt_erase(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); int ret; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (unlikely(argc != 2)) return CMD_RET_USAGE; if (store->gpt_erase) { ret = store->gpt_erase(); return ret; } printf("erase gpt is not prepared\n"); return CMD_RET_USAGE; } /* * Check whether the current boot can be written * ret: 0 disable; 1: enable */ static int do_store_boot_copy_enable(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { enum boot_type_e medium_type = store_get_type(); struct storage_t *store = store_get_current(); int ret = 0, index; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_USAGE; } if (unlikely(argc != 3)) return CMD_RET_USAGE; if (medium_type != BOOT_EMMC) { printf("%s %d not eMMC boot\n", __func__, __LINE__); return CMD_RET_USAGE; } index = simple_strtoul(argv[2], NULL, 16); if (store->boot_copy_enable) { ret = store->boot_copy_enable(index); return ret; } printf("boot copy enable is not prepared\n"); return CMD_RET_USAGE; } static int do_store_rsv_ops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); char *name = NULL; if (!store) { pr_info("%s %d please init your storage device first!\n", __func__, __LINE__); return CMD_RET_FAILURE; } if (!strcmp(argv[2], "erase")) { if (argc == 3) ; else if (argc == 4) name = argv[3]; else return CMD_RET_USAGE; return store->erase_rsv(name); } else if (!strcmp(argv[2], "read") || !strcmp(argv[2], "write")) { u8 cmd = strcmp(argv[2], "read") ? 0 : 1; unsigned long addr = simple_strtoul(argv[4], NULL, 16); size_t size = (size_t)simple_strtoul(argv[5], NULL, 16); name = argv[3]; if (unlikely(argc != 6)) return CMD_RET_USAGE; if (cmd) return store->read_rsv(name, size, (u_char *)addr); else return store->write_rsv(name, size, (u_char *)addr); } else if (!strcmp(argv[2], "protect")) { char *ops; flag = false; if (unlikely(argc != 4 && argc != 5)) return CMD_RET_USAGE; name = (argc == 4) ? NULL : argv[3]; ops = argv[argc - 1]; if (!strcmp(ops, "on")) flag = true; else if (!strcmp(ops, "off")) flag = false; return store->protect_rsv(name, flag); } return CMD_RET_USAGE; } static int do_store_param_ops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct storage_t *store = store_get_current(); if (store && store->param_ops) return store->param_ops(); return 0; } static cmd_tbl_t cmd_store_sub[] = { U_BOOT_CMD_MKENT(init, 4, 0, do_store_init, "", ""), U_BOOT_CMD_MKENT(device, 4, 0, do_store_device, "", ""), U_BOOT_CMD_MKENT(partition, 3, 0, do_store_partition, "", ""), U_BOOT_CMD_MKENT(scrub, 5, 0, do_store_erase, "", ""), U_BOOT_CMD_MKENT(erase, 5, 0, do_store_erase, "", ""), U_BOOT_CMD_MKENT(read, 6, 0, do_store_read, "", ""), U_BOOT_CMD_MKENT(write, 7, 0, do_store_write, "", ""), U_BOOT_CMD_MKENT(write_gpt, 3, 0, do_store_gpt_write, "", ""), U_BOOT_CMD_MKENT(read_gpt, 3, 0, do_store_gpt_read, "", ""), U_BOOT_CMD_MKENT(erase_gpt, 2, 0, do_store_gpt_erase, "", ""), U_BOOT_CMD_MKENT(write_bl2img, 5, 0, do_store_write_bl2img, "", ""), U_BOOT_CMD_MKENT(boot_read, 6, 0, do_store_boot_read, "", ""), U_BOOT_CMD_MKENT(boot_write, 6, 0, do_store_boot_write, "", ""), U_BOOT_CMD_MKENT(boot_erase, 4, 0, do_store_boot_erase, "", ""), U_BOOT_CMD_MKENT(rsv, 6, 0, do_store_rsv_ops, "", ""), U_BOOT_CMD_MKENT(param, 2, 0, do_store_param_ops, "", ""), U_BOOT_CMD_MKENT(boot_copy_enable, 3, 0, do_store_boot_copy_enable, "", ""), }; static int do_store(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { cmd_tbl_t *c; if (argc < 2) return CMD_RET_USAGE; c = find_cmd_tbl(argv[1], cmd_store_sub, ARRAY_SIZE(cmd_store_sub)); if (c) return c->cmd(cmdtp, flag, argc, argv); return CMD_RET_USAGE; } U_BOOT_CMD(store, CONFIG_SYS_MAXARGS, 1, do_store, "STORE sub-system:", "store init [flag]\n" " init storage device\n" "store device [name]\n" " show or set storage device\n" " 'store device' command will list\n" " all valid storage device and print.\n" " 'store device [name]' will set the\n" " [name] device to the current device\n" "store partition\n" " show partitions of current device\n" "store read addr [partition name] off size\n" " read 'size' bytes from offset 'off'\n" " of device/partition 'partition name' to.\n" " address 'addr' of memory.\n" " if partition name not value. read start with\n" " offset in normal logic area,if tpl area exist\n" " read offset at end of tpl area\n" "store write addr [partition name] off size\n" " write 'size' bytes to offset 'off' of\n" " device/partition [partition name] from\n" " address 'addr' of memory.\n" " if partition name not value. write start with\n" " offset in normal logic area,if tpl area exist\n" " write offset at end of tpl area\n" "store write_gpt addr\n" " write gpt from address 'addr'\n" "store read_gpt addr\n" " read gpt to address 'addr'\n" "store erase_gpt\n" " erase primary and secondary gpt\n" "store erase partition name off size.\n" " erase 'size' bytes from offset 'off'\n" " of device/partition [partition name]\n" " partition name must't NULL\n" "store scrub partition name off size.\n" " erase 'size' bytes from offset 'off'\n" " of device/partition [partition name]\n" " includes oob area if the device has.\n" " partition name must't NULL\n" "store erase.chip [flag]\n" " erase all nand chip,except bad block\n" " flag 0 erase all nand chip,except bootloader&rsv\n" " flag 1 erase rsv\n" "store scrub.chip\n" " erase all nand chip,include bad block\n" "store boot_read name addr copy size\n" " read 'size' bytes from 'copy'th backup\n" " in name partition, 'copy' can't be null.\n" " name:\n" " in discrete mode: 'bl2'/'tpl'(fip)\n" " in compact mode: 'bootloader'\n" "store boot_write name addr [copy] size\n" " write 'size' bytes to 'copy'th backup\n" " in [name] partition from address\n" " 'addr' of memory. when the optional 'copy'\n" " is null, it will writes to all copies\n" " name:\n" " in discrete mode:\n" " 'bl2/bl2e/bl2x/ddrfip/tpl(fip), only update part\n" " 'bootloader', update whole uboot.bin, in this case\n" " @copy:if used, must < min(tplCpyNum, Bl2CpyNum), update only the specified copy\n" " if not used, update all the copies of bl2 bl2e bl2x ddrfip tpl!\n" " in compact mode: 'bootloader'\n" "store boot_erase name [copy]\n" " erase the name info from 'copy'th backup\n" " when the optional 'copy' not value, it\n" " will erase all copies.\n" " name:\n" " in discrete mode: \n" " 'bl2'/'tpl'(fip): erase bl2/tpl partition\n" " 'bootloader':erase bl2 + tpl partition\n" " in compact mode: 'bootloader'\n" "store rsv read name addr size\n" " read 'size' bytes 'name' rsv info\n" " to address 'addr' of memory\n" " 'name' could be key/dtb/env etc...\n" "store rsv write name addr size\n" " write 'size' bytes 'name' rsv info\n" " from address 'addr' of memory\n" "store rsv erase name\n" " erase 'name' rsv info\n" " name must't null\n" "store rsv protect name on/off\n" " turn on/off the rsv info protection\n" " name must't null\n" "store param\n" " transfer bl2e/x ddrfip devfip size to kernel in such case like sc2\n" "store boot_copy_enable [boot_index]\n" " check bootloader_x whether enable\n" );