--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019
+ * Broadcom Corp
+ */
+
+#include <stdlib.h>
+#include <command.h>
+#include <common.h>
+#include <environment.h>
+#include <hexdump.h>
+#include <ubi_uboot.h>
+#include <cli.h>
+#include <console.h>
+#include "bca_common.h"
+#include "bcm_bootstate.h"
+#include "spl_env.h"
+#include "bca_sdk.h"
+#include "bcm_secure.h"
+#include "httpd/bcmbca_net.h"
+#include <nand.h>
+#include <mmc.h>
+#if defined(CONFIG_WDT)
+#include <wdt.h>
+#endif
+#if defined(CONFIG_BCMBCA_PMC)
+#include "pmc_drv.h"
+#endif
+
+#define SIZE_OVERHEAD 0x100000UL //1M
+#define BOOTFS_SIZE_BYTES 0x00A00000UL //10M
+#define ROOTFS_SIZE_BYTES 0x02800000UL //40M
+#define SQUASHFS_MAGIC 0x73717368
+#define UBIFS_MAGIC 0x06101831
+#define MIN_IMG_INDEX 1
+#define MAX_IMG_INDEX 2
+
+#define atoi(s) simple_strtol(s, NULL, 0)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Flag indicating whether we want to force an update and disregard any compatibility checks */
+static int forced_updates = 0;
+static char forced_image_media[256] = {0};
+static char forced_boot_media[256] = {0};
+/* Flag to prevent synching of runtime env to loader bin when flashing a new loader */
+static int disable_runtime_env_sync = 0;
+
+typedef int (*flash_fn)( ulong addr, ulong size , int img_index);
+
+typedef struct {
+ char name[20]; /* Name of upgrade bundle component */
+ flash_fn func; /* Function to flash this upgrade bundle component */
+} flashfn_table_entry;
+
+/* Enable CLI commands based on included CMD modules */
+#if defined(CONFIG_CMD_GPT) && defined(CONFIG_CMD_PART) && defined(CONFIG_CMD_MMC) && defined(CONFIG_MMC)
+#define BCA_SDK_EMMC_CMD 1
+#endif
+
+#if defined(CONFIG_CMD_UBI) && defined(CONFIG_CMD_MTD) && defined(CONFIG_NAND)
+#define BCA_SDK_NAND_CMD 1
+#endif
+
+#if defined(CONFIG_CMD_SF) && defined(CONFIG_SPI_FLASH) && defined(CONFIG_DM_SPI_FLASH) && defined(CONFIG_CMD_MTD)
+#define BCA_SDK_SPINOR_CMD 1
+#endif
+
+#if defined(BCA_SDK_SPINOR_CMD)
+static int spinor_load_bootfs(uint32_t bootfs_load_addr );
+static int spinor_restoredefault(void);
+static int write_spinor_partition( char *const partitionname, ulong addr, ulong size );
+static int do_flash_spinor_binary(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int do_flash_spinor_bootfs_rootfs(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int flash_loader_spinor( ulong addr, ulong size);
+#endif
+#ifdef BCA_SDK_EMMC_CMD
+/* EMMC specific routines */
+static int flash_rootfs_emmc( ulong addr, ulong size, int img_index );
+static int flash_bootfs_emmc( ulong addr, ulong size, int img_index );
+static int flash_loader_emmc( ulong addr, ulong size, int img_index );
+static int set_emmc_metadata( char* metadata, int size );
+static int get_emmc_metadata( char* metadata, int size );
+static int emmc_load_bootfs( int img_index, uint32_t bootfs_load_addr );
+static int emmc_rdwr_userdata_part( char * part_name, ulong addr, ulong size, int write );
+static int emmc_rdwr_boot_part( ulong addr, ulong size, int img_index, int write );
+static int emmc_restoredefault(void);
+static int emmc_do_gpt_fixup(void);
+#endif /* BCA_SDK_EMMC_CMD */
+
+#ifdef BCA_SDK_NAND_CMD
+/* NAND Specific routines */
+static int flash_rootfs_nand( ulong addr, ulong size, int img_index );
+static int flash_bootfs_nand( ulong addr, ulong size, int img_index );
+static int flash_loader_nand( ulong addr, ulong size, int img_index );
+static int set_nand_metadata( char* metadata, int size );
+static int get_nand_metadata( char* metadata, int size );
+static int nand_load_fit( int img_index, uint32_t fit_load_addr );
+static int nand_load_bootfs( int img_index, uint32_t bootfs_load_addr );
+static int nand_restoredefault(void);
+#endif /* BCA_SDK_NAND_CMD */
+
+/* Generic routines */
+static unsigned int bcm_handle_mapper(void* fit, char *flash_device, char *flash_opts);
+static int update_flash_parts_from_loader_bin( ulong loader_addr, ulong loader_size );
+static int get_binary_from_bundle( ulong bundle_addr, char * conf_name, char * name,
+ char ** bin_name, ulong * addr, ulong * size );
+static int sync_update_loader_bin_env(ulong loader_addr);
+static int verify_compat_string( const char * compat_str );
+static int do_flash_bins(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int do_boot(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int do_load(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int load_linux_img(int flag, int argc, char *const argv[]);
+static int do_restoredefault(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int do_metadata(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int do_force(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int flash_rootfs( ulong addr, ulong size , int img_index);
+static int flash_bootfs( ulong addr, ulong size , int img_index);
+static int flash_loader( ulong addr, ulong size , int img_index);
+static int do_flash_loader(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int do_flash_bootfs_rootfs( char * bootfs_filename, char * rootfs_filename, int image_index );
+static int do_flash_upgrade_img (cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+static int set_metadata_val( int * committed, int * valid, int * seq );
+static int get_metadata_val( int * committed, int * valid, int * seq );
+static int do_activate(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+char * get_loader_media(void);
+static char * get_image_media(void);
+static int get_active_img_idx(void);
+static int set_active_img_idx( int img_idx);
+#ifdef CONFIG_BCMBCA_HTTPD
+static int do_httpd_start(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+#endif
+#ifdef CONFIG_BCMBCA_XRDP_ETH
+static int do_eth_active_port(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]);
+#endif
+
+/* Local Variables */
+static flashfn_table_entry fn_table[] = {
+ { "bootfs", flash_bootfs },
+ { "rootfs", flash_rootfs },
+ { "loader", flash_loader }
+};
+
+#ifdef CONFIG_BCMBCA_BOARD_SPECIFIC_DT
+#define BCMBCA_BOARDID_MAXSIZE 28
+#define BCMBCA_VOICEBOARDID_MAXSIZE BCMBCA_BOARDID_MAXSIZE
+#include "spl_ddrinit.h"
+static int on_boardid(const char *name, const char *value, enum env_op op, int flags)
+{
+ char boardid[BCMBCA_BOARDID_MAXSIZE+4];
+ int ret = 0;
+ int img_index = 0;
+ long conf, node, offset;
+ uint32_t env_mcb;
+
+ if (forced_updates || ((flags & H_INTERACTIVE) == 0))
+ return 0;
+
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ img_index = get_active_img_idx();
+ if((img_index < MIN_IMG_INDEX) || (img_index > MAX_IMG_INDEX))
+ img_index = MIN_IMG_INDEX;
+ /* Load bootfs to load address */
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ if (nand_load_fit(img_index, load_addr))
+ {
+ printf("Failed to load bootfs\n");
+ return 0;
+ }
+#endif
+ }
+
+ if( ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = emmc_load_bootfs(img_index, load_addr);
+ if (ret)
+ {
+ printf("Failed to load bootfs\n");
+ return 0;
+ }
+#endif
+ }
+
+ conf = fdt_path_offset((void*)load_addr, FIT_IMAGES_PATH);
+ if (conf < 0) {
+ printf("Cannot find /images node: %ld\n", conf);
+ return 0;
+ }
+
+ if (strlen(value) > BCMBCA_BOARDID_MAXSIZE)
+ {
+ printf("boardid is too long, max size is %d\n", BCMBCA_BOARDID_MAXSIZE);
+ return 1;
+ }
+ sprintf(boardid,"fdt_%s", value);
+ for (node = fdt_first_subnode((const void*)load_addr, conf); node >= 0; node = fdt_next_subnode((const void*)load_addr, node))
+ {
+ const char* image_name = fit_get_name((const char*)load_addr, node, NULL);
+
+ if (strcmp(image_name, boardid) == 0)
+ {
+ const uint32_t* memcfg;
+ uint32_t fdt_mcb;
+ const void* fdt;
+ size_t size;
+
+ ret = fit_image_get_data_and_size((const void*)load_addr, node, &fdt, &size);
+ if (ret)
+ {
+ printf("Failed to get FDT\n");
+ return 0;
+ }
+
+ offset = fdt_path_offset(fdt, "/memory_controller");
+ if (offset < 0) {
+ printf("Not found memory_controller node in FDT\n");
+ return 0;
+ }
+
+ memcfg = fdt_getprop(fdt, offset, "memcfg", NULL);
+ if (memcfg == NULL)
+ {
+ printf("Can't find memcfg parameter in DTB\n");
+ return 0;
+ }
+ fdt_mcb = be32_to_cpu(*memcfg);
+ env_mcb = env_get_hex("MCB", 0);
+ if (env_mcb & BP_DDR_CONFIG_OVERRIDE)
+ {
+ printf("MCB sticky bit is set, MCB is not updated\n Current MCB 0x%x, FDT MCB 0x%x\n", env_mcb, fdt_mcb);
+ return 0;
+ }
+ printf("Updating MCB environment from 0x%x to 0x%x\n", env_mcb, fdt_mcb);
+ env_set_hex("MCB", fdt_mcb);
+ env_set("boardid", value);
+ printf("Memory Configuration Changed -- SAVING ENV AND REBOOT NEEDED\n");
+ return 0;
+ }
+ }
+ printf("Error: boardid %s not supported.\nList of supported boards:\n", value);
+ for (node = fdt_first_subnode((const void*)load_addr, conf); node >= 0; node = fdt_next_subnode((const void*)load_addr, node))
+ {
+ char* name = fit_get_name((const char*)load_addr, node, NULL);
+ if ((strncmp("fdt_", name, 4) == 0) && (strcmp("fdt_uboot", name)))
+ printf("%s\n", (name+4));
+ }
+ return 1;
+ case env_op_delete:
+ if (flags & H_FORCE)
+ return 0;
+
+ printf("## boardid may not be deleted\n");
+ return 1;
+ default:
+ return 0;
+ }
+}
+U_BOOT_ENV_CALLBACK(boardid, on_boardid);
+
+static int on_voiceBoardid(const char *name, const char *value, enum env_op op, int flags)
+{
+ char boardid[BCMBCA_BOARDID_MAXSIZE+4];
+ int ret = 0;
+ int img_index = 0;
+ long conf, node, offset;
+ char *pboardid;
+
+ if (forced_updates || ((flags & H_INTERACTIVE) == 0))
+ return 0;
+
+ pboardid = env_get("boardid");
+ if (!pboardid)
+ {
+ printf("boardId must be set first.\n");
+ return 1;
+ }
+
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ img_index = get_active_img_idx();
+ if((img_index < MIN_IMG_INDEX) || (img_index > MAX_IMG_INDEX))
+ img_index = MIN_IMG_INDEX;
+ /* Load bootfs to load address */
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ if (nand_load_fit(img_index, load_addr))
+ {
+ printf("Failed to load bootfs\n");
+ return 0;
+ }
+#endif
+ }
+
+ if( ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = emmc_load_bootfs(img_index, load_addr);
+ if (ret)
+ {
+ printf("Failed to load bootfs\n");
+ return 0;
+ }
+#endif
+ }
+
+ conf = fdt_path_offset((void*)load_addr, FIT_IMAGES_PATH);
+ if (conf < 0) {
+ printf("Cannot find /images node: %ld\n", conf);
+ return 0;
+ }
+
+ if (strlen(value) > BCMBCA_VOICEBOARDID_MAXSIZE)
+ {
+ printf("voiceboardid is too long, max size is %d\n", BCMBCA_VOICEBOARDID_MAXSIZE);
+ return 1;
+ }
+ sprintf(boardid,"fdt_%s", pboardid);
+ for (node = fdt_first_subnode((const void*)load_addr, conf); node >= 0; node = fdt_next_subnode((const void*)load_addr, node))
+ {
+ const char* image_name = fit_get_name((const char*)load_addr, node, NULL);
+
+ if (strcmp(image_name, boardid) == 0)
+ {
+ size_t size;
+ const void* fdt;
+ int i, len, idx, slicCount;
+ const char *sliclist;
+
+ ret = fit_image_get_data_and_size((const void*)load_addr, node, &fdt, &size);
+ if (ret)
+ {
+ printf("Failed to get FDT\n");
+ return 0;
+ }
+
+ offset = fdt_path_offset(fdt, "/bcm_voice");
+ if (offset < 0) {
+ printf("Not found voice node in FDT\n");
+ return 0;
+ }
+ idx = fdt_stringlist_search(fdt, offset, "sliclist", value);
+ /* is the string is found, save it and exit */
+ if (0 <= idx)
+ {
+ env_set("voiceboardid", value);
+ printf("-- saving env and reboot needeD\n");
+ return 0;
+ }
+ printf("%d: %s is not found. idx=%d\n", __LINE__, value, idx);
+ slicCount = fdt_stringlist_count(fdt, offset, "sliclist");
+ printf("slicCount=%d. List of supported daughter cards:\n", slicCount);
+ for (i=0; i < slicCount; i++)
+ {
+ sliclist = fdt_stringlist_get(fdt, offset, "sliclist", i, &len);
+ if (sliclist)
+ printf("%s\n", sliclist);
+ else
+ printf("%d: fdt_stringlist_get failed. len=%d\n", __LINE__, len);
+ }
+ return 1;
+ }
+ }
+ return 1;
+ case env_op_delete:
+ env_set("voiceboardid", "");
+ printf("-- Saving env and reboot needed\n");
+ return 0;
+ default:
+ return 0;
+ }
+}
+U_BOOT_ENV_CALLBACK( voiceboardid, on_voiceBoardid);
+#endif
+
+static int get_active_img_idx( void )
+{
+ int node,len;
+ unsigned int active_img_idx = 0;
+ fdt32_t * nodep = NULL;
+ node = fdt_path_offset(gd->fdt_blob, "/chosen");
+ if (node < 0) {
+ printf("Can't find /chosen node in uboot DTB\n");
+ return node;
+ }
+ nodep = (fdt32_t *)fdt_getprop(gd->fdt_blob, node, "active_image", &len);
+ active_img_idx = fdt32_to_cpu(*(fdt32_t *)nodep);
+
+ return active_img_idx;
+}
+
+static int set_active_img_idx( int img_idx )
+{
+ int node,len;
+ fdt32_t * nodep = NULL;
+ node = fdt_path_offset(gd->fdt_blob, "/chosen");
+ int ret = -1;
+ if (node < 0) {
+ printf("Can't find /chosen node in uboot DTB, device may not boot properly!\n");
+ } else {
+ ret = fdt_setprop_u32(gd->fdt_blob, node, "active_image", img_idx);
+ if(ret)
+ {
+ printf("Could not set active image node in the fdt, device may not boot properly!\n");
+ }
+ }
+ return ret;
+}
+
+/************************************************************
+ * Flash Specific Functions *
+ ************************************************************/
+#ifdef BCA_SDK_EMMC_CMD
+static int emmc_restoredefault(void)
+{
+ ulong part_size_blk, part_start_blk;
+ char cmd[128];
+ int ret = -1;
+
+ /* Switch to user data partition */
+ if ( run_command("mmc dev 0 0", 0) == 0 ) {
+ env_set("part_start_blk", NULL);
+ env_set("part_size_blk", NULL);
+ run_command("part start mmc 0 data part_start_blk", 0);
+ run_command("part size mmc 0 data part_size_blk", 0);
+ part_start_blk = env_get_hex("part_start_blk", 0);
+ part_size_blk = env_get_hex("part_size_blk", 0);
+
+ /* If data exists, delete it */
+ if( part_size_blk ) {
+ sprintf(cmd, "mmc erase 0x%lx 0x%lx", part_start_blk, part_size_blk);
+ ret = run_command(cmd, 0);
+ } else {
+ ret = 0;
+ }
+ } else {
+ printf("Error: Cannot switch to userdata partition!\n");
+ }
+
+ return ret;
+}
+
+static int emmc_rdwr_boot_part( ulong addr, ulong size, int img_index, int write )
+{
+ char cmd[128];
+ ulong num_blocks = 0;
+ ulong block_addr = 0;
+ ulong part_size_blk = 0;
+ int boot_part_num = 1;
+ int ret = -1;
+ struct mmc *mmc = NULL;
+
+ mmc = find_mmc_device(0);
+ if( !mmc ) {
+ printf("Error: Cannot access mmc device!\n");
+ goto emmc_rdwr_boot_part_exit;
+ }
+
+ /* Calculate number of blocks */
+ num_blocks = size/mmc->read_bl_len + (size%mmc->read_bl_len?1:0);
+
+ /* Determine size of raw boot partition */
+ part_size_blk = mmc->capacity_boot/mmc->read_bl_len;
+ if( num_blocks > part_size_blk ) {
+ printf("Error: Insufficient space in boot partition %d for 0x%lx blocks. Partition size is 0x%lx\n", boot_part_num, num_blocks, part_size_blk);
+ goto emmc_rdwr_boot_part_exit;
+ }
+
+ /* Switch to boot partition */
+ sprintf(cmd, "mmc dev 0 %d", boot_part_num);
+ if ( run_command(cmd, 0) ) {
+ printf("Error: Cannot switch to bootpartition %d!\n", boot_part_num);
+ goto emmc_rdwr_boot_part_exit;
+ }
+
+ /* Write to raw boot partition */
+ sprintf(cmd, "mmc %s 0x%lx 0x%lx 0x%lx", (write?"write":"read"), addr, block_addr, num_blocks);
+ ret = run_command(cmd, 0);
+ printf("%s: %s (bootp%d)\n", __FUNCTION__, cmd, boot_part_num);
+
+ /* Switch back to userdata partition */
+ run_command("mmc dev 0 0", 0);
+
+emmc_rdwr_boot_part_exit:
+ if( ret )
+ printf("Error: Failed %s 0x%lx blocks from/to boot partition %d!\n", (write?"writing":"reading"), num_blocks, boot_part_num);
+
+ return ret;
+}
+
+static int emmc_rdwr_userdata_part( char * part_name, ulong addr, ulong size, int write )
+{
+ char cmd[128];
+ ulong num_blocks = 0;
+ ulong block_addr = 0;
+ ulong part_size_blk = 0;
+ int ret = -1;
+ struct mmc *mmc = NULL;
+
+ mmc = find_mmc_device(0);
+ if( !mmc ) {
+ printf("Error: Cannot access mmc device!\n");
+ goto emmc_rdwr_usrdata_part_exit;
+ }
+
+ /* Calculate number of blocks */
+ num_blocks = size/mmc->read_bl_len + (size%mmc->read_bl_len?1:0);
+
+ /* Switch to user data partition */
+ if ( run_command("mmc dev 0 0", 0) ) {
+ printf("Error: Cannot switch to userdata partition!\n");
+ goto emmc_rdwr_usrdata_part_exit;
+ }
+
+ /* Get GPT partition size in blocks */
+ env_set("part_size_blk", NULL);
+ sprintf(cmd, "part size mmc 0 %s part_size_blk", part_name);
+ if(run_command(cmd, 0) == 0) {
+ part_size_blk = env_get_hex("part_size_blk", 0);
+ if( num_blocks > part_size_blk ) {
+ printf("Error: Insufficient space in partition %s for 0x%lx blocks. Partition size is 0x%lx\n", part_name, num_blocks, part_size_blk);
+ goto emmc_rdwr_usrdata_part_exit;
+ }
+ } else {
+ printf("Error: Cannot determine size of GPT partition %s\n", part_name);
+ goto emmc_rdwr_usrdata_part_exit;
+ }
+
+ /* Get start block address of partition */
+ sprintf(cmd, "part start mmc 0 %s part_start_blk", part_name);
+ env_set("part_start_blk", NULL);
+ if(run_command(cmd, 0) == 0) {
+ block_addr = env_get_hex("part_start_blk", 0);
+ sprintf(cmd, "mmc %s 0x%lx 0x%lx 0x%lx", (write?"write":"read"), addr, block_addr, num_blocks);
+ ret = run_command(cmd, 0);
+ printf("%s: %s (%s)\n", __FUNCTION__, cmd, part_name);
+ } else {
+ printf("Error: Cannot determine start block of GPT partition %s\n", part_name);
+ goto emmc_rdwr_usrdata_part_exit;
+ }
+
+emmc_rdwr_usrdata_part_exit:
+ if( ret )
+ printf("Error: Failed %s 0x%lx blocks from/to GPT partition %s!\n", (write?"writing":"reading"), num_blocks, part_name);
+ return ret;
+}
+
+static int flash_rootfs_emmc( ulong addr, ulong size, int img_index )
+{
+ char part_name[128];
+ int ret = CMD_RET_FAILURE;
+
+ if( !addr || !size || img_index < MIN_IMG_INDEX || img_index > MAX_IMG_INDEX )
+ return CMD_RET_USAGE;
+
+ sprintf(part_name, "rootfs%d", img_index);
+ ret = emmc_rdwr_userdata_part( part_name, (ulong)addr, size, 1 );
+
+ return ret;
+}
+
+static int flash_bootfs_emmc( ulong addr, ulong size, int img_index )
+{
+ char part_name[128];
+ int ret = CMD_RET_FAILURE;
+
+ if( !addr || !size || img_index < MIN_IMG_INDEX || img_index > MAX_IMG_INDEX )
+ return CMD_RET_USAGE;
+
+ sprintf(part_name, "bootfs%d", img_index);
+ ret = emmc_rdwr_userdata_part( part_name, (ulong)addr, size, 1 );
+ return ret;
+}
+
+static int flash_loader_emmc( ulong addr, ulong size, int img_index )
+{
+ int ret = -1;
+
+ if( !addr || !size )
+ return CMD_RET_USAGE;
+
+ ret = emmc_rdwr_boot_part( addr, size, img_index, 1);
+
+ return ret;
+}
+
+static int set_emmc_metadata( char* metadata, int size )
+{
+ char part_name[128];
+ int ret;
+ int i;
+
+ for (i = 1; i < 3; i++) {
+ sprintf(part_name, "metadata%d", i);
+ ret = emmc_rdwr_userdata_part( part_name, (ulong)metadata, size, 1 );
+ }
+ return ret;
+}
+
+static int get_emmc_metadata( char* metadata, int size )
+{
+ int ret;
+ int committed = 0;
+ int valid[2] = {0,0};
+ int seq[2] = {-1,-1};
+ int i;
+ char part_name[128];
+
+ for (i = 1; i < 3; i++) {
+ sprintf(part_name, "metadata%d", i);
+ ret = emmc_rdwr_userdata_part( part_name, (ulong)metadata, size, 0 );
+ if (0 == validate_metadata(metadata, valid, &committed, seq)) {
+ break;
+ } else {
+ printf("metadata parse error\n");
+ ret = CMD_RET_FAILURE;
+ }
+ }
+ return ret;
+}
+
+static ulong emmc_get_bootfs_size( char * fit )
+{
+ int images_noffset;
+ int noffset;
+ int ndepth;
+ int count;
+ size_t size;
+ ulong bootfs_size = 0;
+ const void *data;
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ return 0;
+ }
+
+ /* Process all image subnodes */
+ for (ndepth = 0, count = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ count++;
+
+ if (fit_image_get_data_and_size(fit, noffset, &data, &size) == 0) {
+ bootfs_size = ((ulong)data+(ulong)size) - (ulong)fit;
+ }
+ }
+ }
+ printf("Bootfs size is %lu bytes\n", bootfs_size);
+ return bootfs_size;
+}
+
+static int emmc_add_gpt_part( char * name, ulong size )
+{
+ char * current_parts = NULL;
+ char * new_parts = NULL;
+ int ret = -1;
+
+ /* Read partitions into variable */
+ env_set("current_parts", NULL);
+ run_command("gpt read mmc 0 current_parts", 0);
+ current_parts = env_get("current_parts");
+
+ if( strstr(current_parts, name) ) {
+ printf("%s: GPT partition:%s of size:%luMiB exists!\n", __FUNCTION__, name, size);
+ return 0;
+ } else {
+ printf("%s: Adding GPT partition %s of size %luMiB\n", __FUNCTION__, name, size);
+ }
+
+ /* Update partitions */
+ new_parts = malloc(strlen(current_parts) + 1024 );
+ if( new_parts ) {
+ sprintf(new_parts, "%sname=%s,size=%luMiB;", current_parts, name, size);
+ ret = env_set("current_parts", new_parts);
+ free(new_parts);
+ ret = run_command("gpt write mmc 0 $current_parts", 0);
+ ret = run_command("gpt verify mmc 0 $current_parts", 0);
+ } else {
+ printf("%s: Error allocating memory for partition string!\n", __FUNCTION__);
+ }
+
+ //env_set("current_parts", NULL);
+ return ret;
+
+}
+
+/* This function will create GPT partitions if it detects partition sizes specfied via
+ * uboot environment variables. The env variable name has to be in the format:
+ * <partition_name>_vol_size=<size in MiB>
+ * The function will then create GPT partition with name <partition_name> of size <size>
+ *
+ * NOTE: For NAND, equivalent ubi volumes are also created dynamically based on the same
+ * uboot env variables. However, for NAND the volumes are created in the mount-fs.sh linux
+ * startup script instead of in uboot proper.
+ */
+#define VOL_SIZE_STR "_vol_size="
+static int emmc_do_gpt_fixup(void)
+{
+ env_t *ep;
+ char *envbuf = NULL;
+ int ret = -2;
+ int elen;
+ char *config;
+ char * token = NULL;
+ char * token2 = NULL;
+ char * name;
+ int value;
+ ulong token_len = 0;
+
+ config = env_get("env_boot_magic");
+ if (NULL == config)
+ {
+ printf("env_boot_magic missing in the env\n");
+ return -1;
+ }
+ elen = simple_strtoul(config, NULL, 0);
+ elen = max(elen, CONFIG_ENV_SIZE);
+ envbuf = malloc(elen);
+ memset(envbuf, 0, elen);
+
+ if (!envbuf)
+ {
+ printf("memory allocation failed\n");
+ return -2;
+ }
+ ep = (env_t *) (envbuf + 8);
+ ret = env_export(ep);
+
+ /* Search environment for variable names matching <part>_vol_size */
+ token = (char*)(ep->data);
+ while(strlen(token) && (ret == 0) && ((ulong)token < ((ulong)envbuf+elen)))
+ {
+ token_len = strlen(token);
+ if( (token2 = strstr(token, VOL_SIZE_STR)) )
+ {
+ *token2 = '\0';
+ name = token;
+ value = atoi( (char*)((ulong)token2 + strlen(VOL_SIZE_STR)) );
+ printf("%s: Detected env defined partition:%s, of size:%dM\n", __FUNCTION__, name, value);
+ ret = emmc_add_gpt_part(name, value);
+ ret = 0;
+ }
+ token = (char*)((ulong)token + token_len + 1);
+ }
+ free(envbuf);
+ return(ret);
+}
+
+static int do_gpt_fixup(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ return emmc_do_gpt_fixup();
+}
+
+static int emmc_load_bootfs( int img_index, uint32_t bootfs_load_addr )
+{
+ char cmd[128];
+ ulong size;
+ int ret = CMD_RET_FAILURE;
+ int fit_auth= -1;
+
+ /* Set rootfs volume id */
+ int rootfs_partid = (img_index == 1?IMAGE_PART_ID_1:IMAGE_PART_ID_2)+1;
+
+ /* Switch to userdata partition */
+ if( run_command("mmc dev 0 0", 0) == 0 ) {
+ //FIXME: OR skip loading if FIT is already in memory
+ //FIXME: IF FIT is loaded from flash, reverify RSA of header
+ sprintf(cmd, "bootfs%d", img_index);
+
+ /* Get FDT header */
+ size = sizeof(struct fdt_header);
+ ret = emmc_rdwr_userdata_part( cmd, (ulong)bootfs_load_addr, size, 0 );
+
+ /* Retrieve entire FIT header */
+ ret = emmc_rdwr_userdata_part( cmd, (ulong)bootfs_load_addr,
+ bcm_sec_get_reqd_load_size((ulong)bootfs_load_addr), 0 );
+
+ if (!ret) {
+ fit_auth = bcm_sec_validate_fit((void*)bootfs_load_addr, 0x10000);
+ }
+
+ /* Determine size of bootfs from fdt_header and load it */
+ size = emmc_get_bootfs_size((void *)bootfs_load_addr);
+ ret = emmc_rdwr_userdata_part( cmd, (ulong)bootfs_load_addr, size, 0 );
+
+ /* generate mapper parameters */
+ sprintf(cmd,"/dev/mmcblk0p%d", rootfs_partid);
+
+ /* If device mapper not being used, set rootfs_opts manually */
+ if ( (bcm_handle_mapper((void*)(ulong)bootfs_load_addr, cmd, "")) != 0)
+ {
+ /* Set default bootargs */
+ sprintf(cmd, "env set -f rootfs_opts root=/dev/mmcblk0p%d", rootfs_partid);
+ run_command(cmd, 0);
+ }
+
+ if (!fit_auth) {
+ bcm_board_boot_fdt_fixup((void*)bootfs_load_addr);
+ }
+ }
+ return ret;
+}
+
+#endif /* BCA_SDK_EMMC_CMD */
+
+#ifdef BCA_SDK_NAND_CMD
+#define EXTRA_SPC_SUFFIX_STR "_extra_space"
+static uint64_t nand_get_part_extra_bytes(char* partition_prefix)
+{
+ char var_name[128];
+ char * extra_space_str = NULL;
+ uint64_t extra_bytes = 0;
+ unsigned long iargs[4] = {0};
+ char units[4]= {0};
+ sprintf(var_name, "%s%s", partition_prefix, EXTRA_SPC_SUFFIX_STR);
+ extra_space_str = env_get(var_name);
+ if( extra_space_str ) {
+ parse_env_nums(extra_space_str, 1, iargs, units);
+ extra_bytes = ((long long)iargs[0]) << suffix2shift(units[0]);
+ }
+ if( extra_bytes < SIZE_OVERHEAD )
+ extra_bytes = SIZE_OVERHEAD;
+
+ return extra_bytes;
+}
+
+static uint64_t nand_get_avail_space(char * update_vol_name)
+{
+ int i;
+ static struct ubi_device *ubi;
+ static struct ubi_volume *vol;
+ uint64_t vol_size = 0;
+ uint64_t avail_space = 0;
+ int ret = -1;
+
+ ret = run_command("ubi part image", 0);
+ if( ret == 0 ) {
+ ubi = ubi_devices[0];
+ for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
+ if (!ubi->volumes[i])
+ continue; /* Empty record */
+ vol = ubi->volumes[i];
+ if( strcmp(vol->name,update_vol_name) == 0 ) {
+ vol_size = vol->reserved_pebs * vol->usable_leb_size;
+ break;
+ }
+ }
+ avail_space = ubi->avail_pebs * ubi->leb_size + vol_size;
+ }
+ return avail_space;
+}
+
+static int nand_restoredefault(void)
+{
+ int ret = -1;
+ if(run_command("ubi part image", 0) == 0) {
+
+ /* If data exists, delete it */
+ if(run_command("ubi check data", 0) == 0 ) {
+ ret = run_command("ubi remove data", 0);
+ } else {
+ ret = 0;
+ }
+ } else {
+ printf("Error: Cannot attach ubi!\n");
+ }
+ return ret;
+}
+
+static int flash_rootfs_nand( ulong addr, ulong size, int img_index )
+{
+ char cmd[128];
+ int ret = CMD_RET_FAILURE;
+ int rootfs_volid = (img_index == 1? IMAGE_VOL_ID_1:IMAGE_VOL_ID_2) + 1;
+ uint64_t avail_bytes = 0;
+ uint64_t extra_space_bytes = nand_get_part_extra_bytes("rootfs");
+
+ if( !addr || !size || img_index < MIN_IMG_INDEX || img_index > MAX_IMG_INDEX )
+ return CMD_RET_USAGE;
+
+ if(run_command("ubi part image", 0) == 0) {
+
+ /* check if new rootfs will fit in flash */
+ sprintf(cmd, "rootfs%d", img_index);
+ avail_bytes = nand_get_avail_space(cmd);
+ if( avail_bytes < size+extra_space_bytes ) {
+ printf("Error: Insufficient space in NAND for 0x%lx Bytes . Available size is 0x%llx\n", size+extra_space_bytes, avail_bytes);
+ return -1;
+ }
+
+ /* If rootfs1 exists, delete it */
+ sprintf(cmd, "ubi check rootfs%d", img_index);
+ if(run_command(cmd, 0) == 0) {
+ sprintf(cmd, "ubi remove rootfs%d", img_index);
+ run_command(cmd, 0);
+ }
+
+ /* Create rootfs volume */
+ sprintf(cmd, "ubi create rootfs%d %llx dynamic %d", img_index, size+extra_space_bytes,
+ rootfs_volid);
+ ret = run_command(cmd, 0);
+
+ /* Write rootfs data volume */
+ if( ret == 0 ) {
+ sprintf(cmd, "ubi write %lx rootfs%d %lx\n", addr, img_index, size);
+ ret = run_command(cmd, 0);
+ }
+
+ run_command("ubi detach", 0);
+ }
+ return ret;
+}
+
+static int flash_bootfs_nand( ulong addr, ulong size, int img_index )
+{
+ char cmd[128];
+ int ret = CMD_RET_FAILURE;
+ int bootfs_volid = (img_index == 1? IMAGE_VOL_ID_1:IMAGE_VOL_ID_2);
+ int active_img_idx;
+ uint64_t avail_bytes = 0;
+ uint64_t extra_space_bytes = nand_get_part_extra_bytes("bootfs");
+
+ if( !addr || !size || img_index < MIN_IMG_INDEX || img_index > MAX_IMG_INDEX )
+ return CMD_RET_USAGE;
+
+ ret = run_command("ubi part image", 0);
+ if( ret ) {
+ /* Attach failed, check if we are running bootstrap code */
+ active_img_idx = get_active_img_idx();
+ if( active_img_idx == ACTIVE_IMGIDX_BOOTSTRAP ) {
+ /* We are running bootstrap image, wipe Image partition and retry */
+ printf("UBI attach fails for bootstrap image --> erasing IMAGE MTD partition\n");
+ run_command("mtd erase image", 0);
+ ret = run_command("ubi part image", 0);
+ }
+ }
+
+ if(ret == 0) {
+ /* If fit1 exists, delete it */
+ if(run_command("ubi check fit1", 0) == 0)
+ run_command("ubi remove fit1", 0);
+
+ /* check if new bootfs will fit in flash */
+ sprintf(cmd, "bootfs%d", img_index);
+ avail_bytes = nand_get_avail_space(cmd);
+ if( avail_bytes < size+extra_space_bytes ) {
+ printf("Error: Insufficient space in NAND for 0x%lx Bytes . Available size is 0x%llx\n", size+extra_space_bytes, avail_bytes);
+ return -1;
+ }
+
+ /* If bootfs exists, delete it */
+ sprintf(cmd, "ubi check bootfs%d", img_index);
+ if(run_command(cmd, 0) == 0) {
+ sprintf(cmd, "ubi remove bootfs%d", img_index);
+ run_command(cmd, 0);
+ }
+
+ /* Create bootfs volume */
+ sprintf(cmd, "ubi create bootfs%d %llx static %d", img_index, size+extra_space_bytes,
+ bootfs_volid);
+ ret = run_command(cmd, 0);
+
+ /* Write img data */
+ if( ret == 0 ) {
+ sprintf(cmd, "ubi write %lx bootfs%d %lx\n", addr, img_index, size);
+ ret = run_command(cmd, 0);
+ }
+
+ run_command("ubi detach", 0);
+ } else {
+ printf("Error! UBI attach failed!\n");
+ }
+
+ return ret;
+}
+
+
+static int flash_loader_nand( ulong addr, ulong size, int img_index )
+{
+ struct mtd_info * mtd;
+ struct erase_info erase_op = {};
+ loff_t off;
+ int ret;
+ size_t retlen;
+ ulong remaining_bytes = size;
+ mtd = get_mtd_device_nm("loader");
+
+ if( !addr || !size )
+ return CMD_RET_USAGE;
+
+ if( !mtd ) {
+ printf("ERROR: Failed to retrieve MTD device for NAND loader!\n");
+ return -1;
+ }
+
+ if( size > mtd->size ) {
+ printf("ERROR: loader size 0x%08llx is greater than mtd partition size 0x%08llx!\n", size, mtd->size);
+ put_mtd_device(mtd);
+ return -1;
+ }
+
+ (void)img_index;
+
+ /* Block by block write of loader */
+ for( off=0; off < mtd->size; off += mtd->erasesize )
+ {
+ if( remaining_bytes ) {
+ /* Erase block */
+ erase_op.mtd = mtd;
+ erase_op.addr = off;
+ erase_op.len = mtd->erasesize;
+ erase_op.scrub = 0;
+ printf("Erasing next block at 0x%08llx\n", off);
+ ret = mtd_erase(mtd, &erase_op);
+
+ /* Abort if its not a bad block error */
+ if ((ret == -EIO) && erase_op.fail_addr) {
+ printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr);
+
+ /* Truncate image size if we cant fit due to bad block skip */
+ if( remaining_bytes > (mtd->size - off - mtd->erasesize) )
+ remaining_bytes -= (remaining_bytes < mtd->erasesize?remaining_bytes:mtd->erasesize);
+
+ continue;
+ } else if ( ret ) {
+ printf("ERROR: Failed to erase NAND block 0x%08llx\n", off);
+ break;
+ }
+
+ /* write block */
+ printf("Writing next block at 0x%08llx\n", off);
+ ret = mtd_write(mtd, off,
+ (remaining_bytes < mtd->erasesize?remaining_bytes:mtd->erasesize),
+ &retlen, (const uchar*)(addr));
+
+ if( ret ) {
+ printf("ERROR: Failed to write NAND block 0x%08llx\n", off);
+ break;
+ }
+
+ addr += (remaining_bytes < mtd->erasesize?remaining_bytes:mtd->erasesize);
+ remaining_bytes -= (remaining_bytes < mtd->erasesize?remaining_bytes:mtd->erasesize);
+ }
+ else
+ break;
+ }
+
+ if( ret ) {
+ /* Loader upgrade failed for some reason */
+ printf("ERROR: Failed to flash NAND loader! re=%d\n", ret);
+ } else {
+ /* Loader upgrade worked */
+ printf("NAND loader flashed successfully!\n");
+ }
+
+ put_mtd_device(mtd);
+ return ret;
+}
+
+static int set_nand_metadata( char* metadata, int size )
+{
+ char cmd[128];
+ int ret;
+ int i;
+ int volmap[] = {-1,METADATA_VOL_ID_1,METADATA_VOL_ID_2};
+
+ ret = ubi_part("image", NULL);
+ if (ret != 0) {
+ return (ret);
+ }
+ for (i = 1; i < 3; i++) {
+ sprintf(cmd, "ubi remove metadata%d", i);
+ run_command(cmd, 0);
+ sprintf(cmd,
+ "ubi create metadata%d %d static %d", i,
+ METADATA_SIZE + 1024, volmap[i]);
+ run_command(cmd, 0);
+ sprintf(cmd, "metadata%d", i);
+ ubi_volume_write(cmd, metadata, size);
+ }
+ run_command("ubi detach", 0);
+ return ret;
+}
+
+static int get_nand_metadata( char* metadata, int size )
+{
+ int ret;
+ int committed = 0;
+ int valid[2] = {0,0};
+ int seq[2] = {-1,-1};
+ int i;
+ char name[128];
+
+ ret = ubi_part("image", NULL);
+ if (ret != 0) {
+ return (ret);
+ }
+ for (i = 1; i < 3; i++) {
+ sprintf(name, "metadata%d", i);
+ ret = ubi_volume_read(name, metadata, size);
+ printf("read from %s returned %d\n", name, ret);
+ if (0 == validate_metadata(metadata, valid, &committed, seq)) {
+ break;
+ } else {
+ printf("metadata parse error\n");
+ ret = CMD_RET_FAILURE;
+ }
+ }
+ run_command("ubi detach", 0);
+ return ret;
+}
+
+static int nand_load_fit( int img_index, uint32_t fit_load_addr )
+{
+ char cmd[128];
+ int ret = CMD_RET_FAILURE;
+ int fit_auth= -1;
+
+ if(run_command("ubi part image", 0) == 0) {
+ //FIXME: OR skip loading if FIT is already in memory
+ //FIXME: IF FIT is loaded from flash, reverify RSA of header
+ sprintf(cmd, "ubi read %lx bootfs%d", fit_load_addr, img_index);
+ ret = run_command(cmd, 0);
+ /* may be it is just bootstrap image */
+ if (ret) {
+ sprintf(cmd, "ubi read %lx fit1", fit_load_addr);
+ ret = run_command(cmd, 0);
+ }
+ }
+ return ret;
+}
+
+
+static unsigned int bcm_handle_mapper(void* fit, char *flash_device, char *flash_opts)
+{
+ const char *val;
+ char cmd[768];
+ char work[768];
+ char *cp;
+ int off, len;
+ char dmdev[32];
+ unsigned int magic;
+
+ off = fdt_path_offset(fit, "/brcm_rootfs_encrypt");
+ if (off < 0) {
+ return(1);
+ }
+ strcpy(dmdev,"/dev/dm-0");
+ if (val = fdt_getprop(fit, off, "dev", &len)) {
+ strncpy(dmdev, val, len);
+ dmdev[len] = 0;
+ }
+ val = fdt_getprop(fit, off, "type", &len);
+ if (val == NULL) {
+ return(1);
+ }
+ val = fdt_getprop(fit, off, "mapper", &len);
+ if (val == NULL) {
+ return(1);
+ }
+ strncpy(work, val, len);
+ work[len] = 0;
+
+ while (cp = strstr(work,"%DEVICE%")) {
+ strncpy(cmd, work, cp-work);
+ sprintf(&cmd[cp-work], "%s %s", \
+ flash_device, cp+8);
+ strcpy(work,cmd);
+ }
+ if (cp = strstr(work,"%IMAGE_KEY%")) {
+ int i;
+ val = NULL;
+ len = 0;
+ off = fdt_path_offset(gd->fdt_blob, "/trust/key_image_aes");
+ if (off < 0) {
+ printf("ERROR: Can't find /trust/key_image_aes node in boot DTB!\n");
+ }
+ val = (char*)(fdt_getprop(gd->fdt_blob, off, "value", &len));
+ strncpy(cmd, work, cp-work);
+ for (i = 0 ; i < len ; i++) {
+ sprintf(&cmd[cp-work+2*i], "%02x", val[i]);
+ }
+ sprintf(&cmd[cp-work+2*i], "%s", cp+11);
+ strcpy(work,cmd);
+ }
+ sprintf(cmd, "root=%s %s dm-mod.create=\"%s\"", dmdev, flash_opts, work);
+ env_set("rootfs_opts", cmd);
+ return(0);
+}
+
+static int nand_load_bootfs( int img_index, uint32_t bootfs_load_addr )
+{
+ char cmd[128];
+ char device[32];
+ unsigned int magic = 0;
+ int ret = CMD_RET_FAILURE;
+ int fit_auth= -1;
+
+ /* Set rootfs volume id */
+ int rootfs_volid = (img_index == 1?IMAGE_VOL_ID_1:IMAGE_VOL_ID_2)+1;
+
+ if(run_command("ubi part image", 0) == 0) {
+ /* Set default bootargs */
+ /* Determine rootfs type */
+ sprintf(cmd, "ubi read %lx bootfs%d", bootfs_load_addr, img_index);
+ ret = run_command(cmd, 0);
+ if (!ret) {
+ fit_auth = bcm_sec_validate_fit((void*)bootfs_load_addr, 0x10000);
+ }
+
+ sprintf(device,"/dev/ubiblock0_%d", rootfs_volid);
+ sprintf(cmd,"ubi.mtd=1 ubi.block=0,%d rootfstype=squashfs", rootfs_volid);
+ if (bcm_handle_mapper((void*)(ulong)bootfs_load_addr, device, cmd) == 0)
+ {
+ /* mapper has set up the whole thing */
+ if (!fit_auth) {
+ bcm_board_boot_fdt_fixup((void*)bootfs_load_addr);
+ }
+ return(0);
+ }
+
+ sprintf(cmd, "ubi read %lx rootfs%d %d", &magic, img_index, (int)sizeof(unsigned int));
+ if (run_command(cmd, 0) == 0) {
+ if( magic == UBIFS_MAGIC ) {
+ sprintf(cmd, "env set -f rootfs_opts root=ubi:rootfs%d ubi.mtd=1 rootfstype=ubifs", img_index);
+ run_command(cmd, 0);
+ }
+ else if ( magic == SQUASHFS_MAGIC ) {
+ sprintf(cmd, "env set -f rootfs_opts root=/dev/ubiblock0_%d ubi.mtd=1 ubi.block=0,%d rootfstype=squashfs", rootfs_volid, rootfs_volid);
+ run_command(cmd, 0);
+ } else {
+ printf("ERROR: Invalid rootfs detected in volume rootfs1! Boot aborted!\n");
+ return ret;
+ }
+ } else {
+ printf("ERROR: Cannot determine rootfs type! Boot aborted!\n");
+ return ret;
+ }
+
+ if (!fit_auth && magic == SQUASHFS_MAGIC ) {
+ bcm_board_boot_fdt_fixup((void*)bootfs_load_addr);
+ }
+ }
+ return ret;
+}
+#endif /* BCA_SDK_NAND_CMD */
+#if defined(BCA_SDK_SPINOR_CMD)
+static int spinor_load_bootfs(uint32_t bootfs_load_addr)
+{
+ int ret= -1;
+ struct mtd_info *mtd;
+ size_t retlen;
+ int fit_auth;
+
+ mtd_probe_devices();
+ mtd = get_mtd_device_nm(BOOTFS_PART);
+ if (IS_ERR_OR_NULL(mtd)){
+ debug("%s:MTD device %s not found, ret %ld\n",__func__, BOOTFS_PART,
+ PTR_ERR(mtd));
+ return ret;
+ }
+
+ ret = mtd_read(mtd,0,mtd->size,&retlen,(u_char*)bootfs_load_addr );
+
+ if (!ret) {
+ fit_auth = bcm_sec_validate_fit((void*)bootfs_load_addr, 0x10000);
+ }
+
+ /* If device mapper not being used, set the rootfs_opts manually */
+ if (bcm_handle_mapper((void*)(ulong)bootfs_load_addr, "/dev/mtdblock3", "rootfstype=squashfs") != 0) {
+ env_set("rootfs_opts","root=/dev/mtdblock3 rootfstype=squashfs");
+ }
+
+ if (!fit_auth) {
+ bcm_board_boot_fdt_fixup((void*)bootfs_load_addr);
+ }
+
+ put_mtd_device(mtd);
+ return ret;
+}
+static int spinor_restoredefault(void)
+{
+ struct mtd_info *mtd;
+ struct erase_info ei;
+ int ret;
+
+ mtd_probe_devices();
+ mtd = get_mtd_device_nm(DATA_PART);
+ if (IS_ERR_OR_NULL(mtd)){
+ printf("ERROR!!:failed to get data partition!!\n");
+ return CMD_RET_FAILURE;
+ }
+
+ memset(&ei, 0, sizeof(ei));
+ ei.mtd = mtd;
+ ei.addr = 0;
+ ei.len = mtd->size;
+ ret = mtd_erase(mtd, &ei);
+ if (ret){
+ printf("ERROR!!: failed to restore to default!!\n");
+ ret = CMD_RET_FAILURE;
+ }
+ else
+ printf("Restore to default done.\n");
+
+ put_mtd_device(mtd);
+ return ret;
+}
+
+static int flash_loader_spinor( ulong addr, ulong size)
+{
+ int ret= -1;
+ struct mtd_info *mtd;
+ struct erase_info ei;
+ size_t retlen;
+ char *config;
+ u_char *envbuf = NULL;
+ char *found = NULL;
+ int elen;
+ int i;
+ size_t wr_len;
+ char *c;
+
+ if( !addr || !size )
+ return CMD_RET_USAGE;
+ mtd_probe_devices();
+ mtd = get_mtd_device_nm(LOADER_PART);
+ if (IS_ERR_OR_NULL(mtd)){
+ printf("%s:MTD device %s not found, ret %ld\n",__func__, LOADER_PART,
+ PTR_ERR(mtd));
+ return ret;
+ }
+
+ config = env_get("env_boot_magic");
+ if (NULL != config){
+ elen = simple_strtoul(config, NULL, 0);
+ found = malloc(strlen(config) + 1);
+ if (found){
+ strcpy(found, config);
+ envbuf = malloc(elen + 12);
+ if(envbuf){
+ strtok(found, "@");
+ while ((c = strtok(NULL, ","))) {
+ i = simple_strtoul(c, NULL, 0);
+ debug("read from %x\n", i);
+ wr_len = elen+12;
+ debug("read len %x\n", wr_len);
+ if( mtd_read(mtd,i,wr_len,&retlen, envbuf)){
+ debug("%s:MTD device %s read fail\n",__func__, LOADER_PART);
+ continue;
+ }
+ /*assume addr + i will not cause any issue*/
+ memcpy(addr+i, envbuf, wr_len);
+ /*need this?*/
+ if( size < (i + wr_len)){
+ debug("%s:Change original size from %ld to %d \n",__func__,size, i + wr_len);
+ size = i + wr_len;
+ }
+ }
+ free(envbuf);
+ }
+ free(found);
+ }
+ }
+
+ printf("\nErasing MTD partition %s...\n",LOADER_PART);
+ memset(&ei, 0, sizeof(ei));
+ ei.mtd = mtd;
+ ei.addr = 0;
+ ei.len = mtd->size;
+ ret = mtd_erase(mtd, &ei);
+ if (ret){
+ debug("%s:erase MTD device %s fail, ret %d\n",__func__, LOADER_PART,
+ ret);
+ goto done;
+ }
+
+ printf("Writing MTD partition %s...\n",LOADER_PART);
+ ret = mtd_write(mtd, 0, size, &retlen, addr);
+ if (ret){
+ debug("%s:write MTD device %s fail, ret %d\n",__func__, LOADER_PART,
+ ret);
+ }
+ debug("%s:Erase/write MTD device %s done, ret %d\n",__func__, LOADER_PART,
+ ret);
+done:
+ put_mtd_device(mtd);
+ return ret;
+
+}
+
+static int write_spinor_partition( char *const partitionname, ulong addr, ulong size )
+{
+ int ret= -1;
+ struct mtd_info *mtd;
+ struct erase_info ei;
+ size_t retlen;
+
+ if( !addr || !size )
+ return CMD_RET_USAGE;
+
+ mtd_probe_devices();
+ mtd = get_mtd_device_nm(partitionname);
+ if (IS_ERR_OR_NULL(mtd)){
+ debug("%s:MTD device %s not found, ret %d\n",__func__, partitionname,
+ PTR_ERR(mtd));
+ return ret;
+ }
+ printf("\nErasing MTD partition %s...\n",partitionname);
+ memset(&ei, 0, sizeof(ei));
+ ei.mtd = mtd;
+ ei.addr = 0;
+ ei.len = mtd->size;
+ ret = mtd_erase(mtd, &ei);
+ if (ret){
+ debug("%s:erase MTD device %s fail, ret %d\n",__func__, partitionname,
+ ret);
+ goto done;
+ }
+
+ printf("Writing MTD partition %s...\n",partitionname);
+ ret = mtd_write(mtd, 0, size, &retlen, (u_char*)addr);
+ if (ret){
+ debug("%s:write MTD device %s fail, ret %d\n",__func__, partitionname,
+ ret);
+ }
+done:
+ put_mtd_device(mtd);
+ return ret;
+}
+
+static int do_flash_spinor_binary(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ char cmd[128];
+ ulong size;
+ ulong addr;
+
+ /* Download binary image */
+ sprintf(cmd, "tftp %lx %s", load_addr, argv[1]);
+ if( run_command(cmd, 0) == 0 ) {
+ addr = env_get_hex("fileaddr", 0);
+ size = env_get_hex("filesize", 0);
+ write_spinor_partition(SPIFLASH_MTDNAME, addr, size);
+ } else
+ printf("ERROR!!: Failed to tftp spinor binary!!\n");
+
+ return 0;
+}
+
+static int do_flash_spinor_bootfs_rootfs(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ char filename[30];
+ int flash_fit=0;
+ int ret = CMD_RET_FAILURE;
+ char cmd[128];
+ ulong size;
+ ulong addr;
+
+
+ /* Parse arguments */
+ if ( strcmp(argv[0], "flash_spinor_fit") == 0) {
+ flash_fit=1;
+ sprintf(filename, "brcm_full_linux.itb");
+ } else {
+ sprintf(filename, "rootfs.squashfs");
+ }
+
+ sprintf(cmd, "tftp %lx %s\n", load_addr, filename);
+ if( run_command(cmd, 0) == 0 ) {
+ size = env_get_hex("filesize", 0);
+ addr = env_get_hex("fileaddr", 0);
+ if(flash_fit){
+ ret = write_spinor_partition(BOOTFS_PART, addr, size);
+ }
+ else{
+ ret = write_spinor_partition(ROOTFS_PART, addr, size);
+ }
+ }
+ else
+ printf("ERROR!!: Failed to tftp rootfs binary!!\n");
+
+ return ret;
+}
+#endif /*BCA_SDK_SPINOR_CMD*/
+
+/************************************************************
+ * Generic Functions *
+ ************************************************************/
+static int sync_update_loader_bin_env(ulong loader_addr)
+{
+ env_t *ep;
+ uint32_t calc_crc;
+ char *envbuf = NULL;
+ uint32_t *envintp;
+ int ret = -2;
+ int i;
+ loff_t off;
+ size_t rdlen;
+ uint32_t magichdr[3];
+ int num_env_found = 0;
+ char * config;
+
+ /* Search loader in memory for env headers */
+ for (off = 0; off < (loff_t)env_boot_magic_search_size(); off += 4096) {
+ rdlen = 12;
+ memcpy((char*)magichdr, (char*)loader_addr + off, rdlen);
+ if (magichdr[0] != BOOT_MAGIC_MAGIC) {
+ continue;
+ } else {
+ /* Verify CRC */
+ rdlen = magichdr[1];
+ ep = (env_t *) ((char*)loader_addr + off + 8);
+ calc_crc = the_env_crc32(0, ep->data, rdlen - 4);
+ if( ep->crc == calc_crc ) {
+ num_env_found++;
+ } else {
+ continue;
+ }
+ }
+
+ /* Create synced env blob */
+ if(num_env_found == 1)
+ {
+ /* Export environment to embed in new loader */
+ envbuf = malloc(max(rdlen + 12, CONFIG_ENV_SIZE + 12));
+ if( !envbuf ) {
+ printf("ERROR: Failed to allocate mem for env!\n");
+ ret = -1;
+ break;
+ }
+ ep = (env_t *) (envbuf + 8);
+ envintp = (uint32_t *) envbuf;
+
+ /* Delete boot magic string before exporting env */
+ config = env_get("env_boot_magic");
+ env_set("env_boot_magic", NULL);
+ ret = env_export(ep);
+ if( ret ) {
+ printf("ERROR: Failed to export env!\n");
+ env_set("env_boot_magic", config);
+ break;
+ }
+
+ for (i = CONFIG_ENV_SIZE; i < rdlen; i++) {
+ envbuf[12 + i] = 0xff;
+ }
+ calc_crc = the_env_crc32(0, ep->data, rdlen - 4);
+ memcpy(&ep->crc, &calc_crc, sizeof(calc_crc));
+ envintp[0] = BOOT_MAGIC_MAGIC;
+ envintp[1] = rdlen;
+ }
+
+ /* Write synched env back to loader binary */
+ printf("Updating env in loader bin at 0x%lx\n", (long)off);
+ memcpy((char*)loader_addr + off, envbuf, rdlen+12);
+ }
+
+ if(envbuf)
+ free(envbuf);
+
+ if(!num_env_found)
+ ret = -1;
+
+ return ret;
+}
+
+char * get_loader_media(void)
+{
+ int node,len;
+ char *media = NULL;
+
+ if(forced_updates && strlen(forced_boot_media)) {
+ media = forced_boot_media;
+ printf("WARNING: forced_updates == 1, forcing boot media to %s!\n", media);
+ } else {
+ node = fdt_path_offset(gd->fdt_blob, "/chosen");
+ if (node < 0) {
+ printf("ERROR: Can't find /chosen node in cboot DTB! Cannot determine boot media!\n");
+ return media;
+ }
+ media = (char*)(fdt_getprop(gd->fdt_blob, node, "boot_device", &len));
+ }
+ return media;
+}
+
+static char * get_image_media(void)
+{
+ char *cp = NULL;
+ char *media = NULL;
+
+ if(forced_updates && strlen(forced_image_media)) {
+ media = forced_image_media;
+ printf("WARNING: forced_updates == 1, forcing image media to %s!\n", media);
+ } else {
+ cp = env_get("IMAGE");
+ if (NULL != cp)
+ {
+ unsigned long iargs[4];
+ char units[4];
+ parse_env_string_plus_nums(cp, &media, 4, iargs, units);
+ }
+ else
+ printf("ERROR: Can't find IMAGE env parameter! Cannot determine image media!\n");
+ }
+
+ return media;
+}
+
+static int flash_rootfs( ulong addr, ulong size , int img_index)
+{
+ int ret = -1;
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = flash_rootfs_nand(addr, size, img_index);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = flash_rootfs_emmc(addr, size, img_index);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_SPINOR) == 0 ) ) {
+#ifdef BCA_SDK_SPINOR_CMD
+ ret = write_spinor_partition(ROOTFS_PART, addr, size);
+#endif
+ }
+
+ if( ret )
+ printf("ERROR: Failed to flash bootfs binary!\n");
+
+ return ret;
+
+}
+static int flash_bootfs( ulong addr, ulong size , int img_index)
+{
+ int ret = -1;
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = flash_bootfs_nand(addr, size, img_index);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = flash_bootfs_emmc(addr, size, img_index);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_SPINOR) == 0 ) ) {
+#ifdef BCA_SDK_SPINOR_CMD
+ ret = write_spinor_partition(BOOTFS_PART, addr, size);
+#endif
+ }
+ if( ret )
+ printf("ERROR: Failed to flash bootfs binary!\n");
+
+ return ret;
+}
+static int flash_loader( ulong addr, ulong size , int img_index)
+{
+ int ret = -1;
+ char * config;
+
+ /* Synch uboot env to loader binary */
+ if( disable_runtime_env_sync ) {
+ printf("WARNING: Not synching runtime env to loader board_spl_fit_pre_load!\n");
+ } else {
+ if( sync_update_loader_bin_env(addr) ) {
+ printf("ERROR: Could not sync runtime env to loader bin!\n");
+ return ret;
+ }
+ }
+
+ if( strcasecmp(get_loader_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = flash_loader_nand(addr, size, img_index);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_loader_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = flash_loader_emmc(addr, size, img_index);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_loader_media(), FLASH_DEV_STR_SPINOR) == 0 ) ) {
+#ifdef BCA_SDK_SPINOR_CMD
+ ret = flash_loader_spinor(addr, size);
+#endif
+ }
+ if( disable_runtime_env_sync ) {
+ printf("WARNING: Not updating runtime env from flashed loader!\n");
+ disable_runtime_env_sync = 0;
+ } else {
+ /* Since sync was successful, we need to scan loader
+ * for boot magic and update runtime env */
+ env_relocate();
+ env_set("fileaddr", NULL);
+ env_save();
+ }
+
+ if( ret )
+ printf("ERROR: Failed to flash loader binary!\n");
+
+ return ret;
+}
+
+static int set_metadata_val( int * committed, int * valid, int * seq )
+{
+ char* b;
+ uint32_t *d, crc;
+ env_t * ep;
+ int i;
+ int ret = -1;
+
+ b = malloc(METADATA_SIZE + 2048);
+ d = (uint32_t *) b;
+ ep = (env_t *) & d[2];
+ d[0] = METADATA_SIZE;
+ d[1] = METADATA_SIZE;
+ i = sprintf((char*)ep->data, "COMMITTED=%d",*committed) + 1;
+ i = i + sprintf((char*)&ep->data[i], "VALID=%d,%d",valid[0],valid[1]) + 1;
+ i = i + sprintf((char*)&ep->data[i], "SEQ=%d,%d",seq[0],seq[1]) + 1;
+ ep->data[i] = '\0';
+ crc = the_env_crc32(0, ep->data, (d[0] - 4) & 0xffff);
+ /*
+ * We can't use plain crc32 because someone redefines it??
+ * crc = crc32(0, ep->data, (d[0] - 4) & 0xffff);
+ */
+ memcpy(&ep->crc, &crc, sizeof(crc));
+
+ /* Flash metadata */
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = set_nand_metadata(b, METADATA_SIZE + 16);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = set_emmc_metadata(b, METADATA_SIZE + 16);
+#endif
+ }
+
+ printf("Setting committed %d valid %d,%d seq %d,%d\n", *committed, valid[0], valid[1], seq[0], seq[1]);
+ free(b);
+ return ret;
+}
+
+static int get_metadata_val( int * committed, int * valid, int * seq )
+{
+ char *b = malloc(MAX_METADATA_SIZE);
+ int ret = -1;
+
+ /* Read metadata from flash */
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = get_nand_metadata( b, MAX_METADATA_SIZE);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = get_emmc_metadata(b, MAX_METADATA_SIZE);
+#endif
+ }
+
+ /* Validate metadata */
+ ret = validate_metadata(b, valid, committed, seq);
+ free(b);
+ printf("Getting committed %d valid %d,%d seq %d,%d\n", *committed, valid[0], valid[1], seq[0], seq[1]);
+ return ret;
+}
+
+int commit_image( int img_index )
+{
+ int committed = 0;
+ int valid[2] = {0,0};
+ int seq[2] = {-1,-1};
+
+ /*Return directly for SPI Nor*/
+ if( strcmp(get_image_media(), FLASH_DEV_STR_SPINOR) == 0)
+ return 0;
+
+ /* Get committed image */
+ get_metadata_val(&committed, valid, seq);
+
+ /* update committed image */
+ committed = img_index;
+ valid[img_index-1] = img_index;
+ seq[img_index-1] = (seq[(img_index == 1) ? 1 : 0] + 1) % 1000; // set newly written image sequence number one greater than other image
+
+ /* Set committed image */
+ set_metadata_val(&committed, valid, seq);
+
+ return 0;
+}
+
+int get_img_index_for_upgrade(int flag)
+{
+ int committed = 0;
+ int valid[2] = {0,0};
+ int seq[2] = {-1,-1};
+ (void) flag;
+ int img_index = get_active_img_idx();
+
+ /*Return 1 for SPI Nor*/
+ if( strcmp(get_image_media(), FLASH_DEV_STR_SPINOR) == 0 )
+ return 1;
+
+ /* If we know the active image, always write to the inactive image */
+ if( img_index ) {
+ return( (img_index==1)?2:1 );
+ }
+
+ /* If we cannot determine active image, then get non committed image */
+ get_metadata_val(&committed, valid, seq);
+ if( !committed ) {
+ /* If no commited images then we will flash to the 1st img index */
+ return 1;
+ } else {
+ /* If we have a committed image, then we will upgrade the uncommitted one */
+ return (committed == 1? 2: 1);
+ }
+}
+
+#ifndef CONFIG_LOAD_FIT_OFFSET
+#define CONFIG_LOAD_FIT_OFFSET SZ_16M
+#endif
+
+static int load_linux_img( int flag, int argc, char *const argv[])
+{
+ char cmd[128];
+ char * board_id = NULL;
+ int img_index = 0;
+ uint32_t bootfs_load_addr = load_addr + CONFIG_LOAD_FIT_OFFSET;
+ int ret = -1;
+
+ if( argc == 1 ) {
+ img_index = get_active_img_idx();
+ } else if( argc > 1 ) {
+ if( strlen(argv[1]) == 1 )
+ img_index = *argv[1] - '0';
+ else {
+ board_id = argv[1];
+ img_index = get_active_img_idx();
+ }
+
+ if( argc > 2 ) {
+ board_id = argv[2];
+ }
+ }
+
+ if( img_index < MIN_IMG_INDEX || img_index > MAX_IMG_INDEX ) {
+ printf("ERROR: Invalid Image Index specified!\n");
+ return CMD_RET_FAILURE;
+ }
+
+#if defined(CONFIG_BCM_BOOTSTATE)
+ /* bcmbca_set_boot_reason(BCM_BOOT_REASON_WATCHDOG | BCM_BOOT_PHASE_LINUX_START | (bcmbca_get_boot_reason() & 0xffff0000) ); */
+#endif
+ /* Load bootfs to load address */
+ if( strcasecmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = nand_load_bootfs(img_index, bootfs_load_addr);
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = emmc_load_bootfs(img_index, bootfs_load_addr);
+ ret = emmc_do_gpt_fixup();
+#endif
+ }
+
+ if( ret && ( strcasecmp(get_image_media(), FLASH_DEV_STR_SPINOR) == 0 ) ) {
+#ifdef BCA_SDK_SPINOR_CMD
+ ret = spinor_load_bootfs(bootfs_load_addr);
+#endif
+ }
+
+ if( ret == 0 ) {
+#if defined(CONFIG_WDT)
+ if (gd->watchdog_dev)
+ wdt_stop(gd->watchdog_dev);
+#endif
+ if(!board_id)
+ board_id = env_get("boardid");
+
+ /* Load binaries */
+ sprintf(cmd, "/configurations/conf_lx_%s", board_id);
+ if(board_id && (fdt_path_offset((void *)bootfs_load_addr, cmd) >= 0))
+ sprintf(cmd, "bootm start %lx#conf_lx_%s; bootm loados; bootm prep;", bootfs_load_addr, board_id);
+ else
+ sprintf(cmd, "bootm start %lx#conf_linux; bootm loados; bootm prep;", bootfs_load_addr);
+
+ run_command(cmd, 0);
+ } else {
+ printf("ERROR: Failed to load bootfs%d!\n", img_index);
+ }
+
+ return ret;
+}
+
+static int do_load(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if( load_linux_img( flag, argc, argv ) == 0 ) {
+ printf("\nAll Image components have been loaded to DDR:\n");
+ printf(" - To edit FDT: 'fdt <fdt cmds> ..'\n");
+ printf(" - To launch Linux: 'bootm go'\n");
+ } else
+ printf("Linux image loading Failed!\n");
+
+ return 0;
+}
+
+static int do_boot(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ if( load_linux_img( flag, argc, argv ) == 0 )
+ run_command("bootm go\n", 0);
+ else
+ printf("Linux image booting Failed!\n");
+
+ return 0;
+}
+
+static int do_flash_loader(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ char cmd[128];
+ const char *chip_num;
+ ulong size;
+ ulong addr;
+
+ /* Determine chip number */
+ chip_num = strstr(CONFIG_SYS_SOC, "bcm");
+ chip_num += strlen("bcm");
+
+ if( strcasecmp(get_loader_media(), FLASH_DEV_STR_NAND) == 0 ) {
+ sprintf(cmd, "tftp %lx loader_test_nand_%s.bin\n", load_addr, chip_num);
+ }
+
+ if( ( strcasecmp(get_loader_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+ sprintf(cmd, "tftp %lx loader_test_emmc_%s.bin\n", load_addr, chip_num);
+ }
+
+ if( ( strcasecmp(get_loader_media(), FLASH_DEV_STR_SPINOR) == 0 ) ) {
+ sprintf(cmd, "tftp %lx loader_test_spinor_%s.bin\n", load_addr, chip_num);
+ }
+
+ if( run_command(cmd, 0) == 0 ) {
+ size = env_get_hex("filesize", 0);
+ addr = env_get_hex("fileaddr", 0);
+ flash_loader(addr, size, 0);
+ } else
+ printf("ERROR!!: Failed to tftp loader binary!!\n");
+
+ return 0;
+}
+
+static int do_flash_bootfs_rootfs( char * bootfs_filename, char * rootfs_filename, int img_index )
+{
+ char cmd[128];
+ ulong size;
+ ulong addr;
+ int ret = CMD_RET_FAILURE;
+
+ /* Write bootfs */
+ if(bootfs_filename) {
+ sprintf(cmd, "tftp %lx %s", load_addr, bootfs_filename);
+ if( run_command(cmd, 0) == 0 ) {
+ size = env_get_hex("filesize", 0);
+ addr = env_get_hex("fileaddr", 0);
+ ret = flash_bootfs(addr, size, img_index);
+ } else
+ printf("ERROR!!: Failed to tftp FIT image!!\n");
+ }
+
+ /* Write rootfs */
+ if(rootfs_filename) {
+ sprintf(cmd, "tftp %lx %s\n", load_addr, rootfs_filename);
+
+ if( run_command(cmd, 0) == 0 ) {
+ size = env_get_hex("filesize", 0);
+ addr = env_get_hex("fileaddr", 0);
+ ret = flash_rootfs(addr, size, img_index);
+ } else
+ printf("ERROR!!: Failed to tftp rootfs binary!!\n");
+ }
+
+ return ret;
+}
+
+static int do_flash_bins(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ char * rootfs_fname = NULL;
+ char * bootfs_fname = NULL;
+ int img_index = 0;
+ int ret = CMD_RET_FAILURE;
+
+ /* Parse arguments */
+ if ( (strcmp(argv[0], "flash_bootfs_raw") == 0) ) {
+ bootfs_fname = argv[1];
+ }
+ if( (strcmp(argv[0], "flash_rootfs_raw") == 0) ) {
+ rootfs_fname = argv[1];
+ }
+
+ if( argc >= 2 ) {
+ if( (argc == 3) && (strlen(argv[2]) == 1) )
+ img_index = *argv[2] - '0';
+ else
+ img_index = get_img_index_for_upgrade(0);
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ ret = do_flash_bootfs_rootfs(bootfs_fname, rootfs_fname, img_index);
+
+ return ret;
+}
+
+static int verify_compat_string( const char * compat_str )
+{
+ const char *chip_num;
+ char * flash_type;
+ char * token = NULL;
+#ifdef BCA_SDK_NAND_CMD
+ char flash_type_full[20];
+ struct mtd_info *mtd = NULL;
+#endif
+
+ /* Early return if forced updates are enabled */
+ if( forced_updates ) {
+ printf("WARNING: Skipping all compatibility checks due to forced updates being enabled!\n");
+ return 0;
+ }
+
+ /* Determine chip number */
+ chip_num = strstr(CONFIG_SYS_SOC, "bcm");
+ chip_num += strlen("bcm");
+
+ /* Determine flash type matches*/
+ flash_type = get_image_media();
+
+ if( strcmp(flash_type, FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ mtd = get_nand_dev_by_index(0);
+ if (!mtd) {
+ printf("ERROR: Cannot determine NAND erase block size!\n");
+ return CMD_RET_FAILURE;
+ }
+ sprintf(flash_type_full, "%s%d", flash_type, mtd->erasesize >> 10 );
+#endif
+ }
+
+ /* Check compat string */
+ token = strtok((char *)compat_str,";");
+ while( token ) {
+ if( strstr(token, "chip=")) {
+ token += strlen("chip=");
+ if( strcasecmp(token, chip_num) ) {
+ printf("ERROR: Img bundle is for %s, current chip is %s\n", token, chip_num);
+ return -1;
+ }
+ } else if( strstr(token, "flash=")) {
+ token += strlen("flash=");
+ if( strcasecmp(token, flash_type) ) {
+ if( strcmp(flash_type, FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ if( strcasecmp(token, flash_type_full) )
+ {
+ printf("ERROR: Img bundle is for %s, current flash is %s\n", token, flash_type_full);
+ return -1;
+ }
+#endif
+ } else {
+ printf("ERROR: Img bundle is for %s, current flash is %s\n", token, flash_type);
+ return -1;
+ }
+ }
+ }
+ token = strtok(NULL,";");
+ }
+ return 0;
+}
+
+static int get_binary_from_bundle( ulong bundle_addr, char * conf_name, char * name,
+ char ** bin_name, ulong * addr, ulong * size )
+{
+ char path[128];
+ int conf_nodeoffset = 0;
+ int nodeoffset = 0;
+ int len;
+ int ret = -1;
+
+ if ( !conf_name || !name || !bin_name ) {
+ printf("ERROR: Invalid conf_name %p, bin_name %p, name %p\n",
+ conf_name, bin_name, name);
+ return ret;
+ }
+
+ /* retrieve configuration node */
+ sprintf(path, "/configurations");
+ sprintf(path, "%s/%s", path, conf_name);
+ conf_nodeoffset = fdt_path_offset((void *)bundle_addr, path);
+ if( conf_nodeoffset < 0 ) {
+ printf("ERROR: %s node not found in bundle!\n", conf_name);
+ return ret;
+ }
+
+ /* Get actual name of fit node for bundle component */
+ *bin_name = fdt_getprop( (void *)bundle_addr, conf_nodeoffset, name, &len);
+ if( !*bin_name ) {
+ printf("INFO: %s not found in configuration %s ...skipping!\n", name, conf_name);
+ return ret;
+ }
+
+ /* Retrieve node offset for bundle component */
+ sprintf(path, "/images/%s", *bin_name);
+ nodeoffset = fdt_path_offset((void *)bundle_addr, path);
+ if( nodeoffset < 0 ) {
+ printf("ERROR: %s node not found in bundle!\n", path);
+ return ret;
+ }
+
+ /* Get location and size of binary's data */
+ fit_image_get_data_and_size((void *)bundle_addr, nodeoffset, (const void**)addr, size);
+ if( !*size ) {
+ printf("ERROR: %s data not found in bundle!\n", *bin_name);
+ return ret;
+ }
+ return 0;
+}
+
+static int update_flash_parts_from_loader_bin( ulong loader_addr, ulong loader_size ) {
+ env_t *ep;
+ uint32_t calc_crc;
+ char *envbuf = NULL;
+ uint32_t *envintp;
+ int ret = -2;
+ int i;
+ loff_t off;
+ size_t rdlen;
+ uint32_t magichdr[3];
+ char cmd[128];
+
+ /* Search loader in memory for env headers */
+ for (off = 0; off < (loff_t)env_boot_magic_search_size(); off += 4096) {
+ /* Search loader bin for environment */
+ rdlen = 12;
+ memcpy((char*)magichdr, (char*)loader_addr + off, rdlen);
+ if (magichdr[0] != BOOT_MAGIC_MAGIC) {
+ continue;
+ } else {
+ /* Verify CRC */
+ rdlen = magichdr[1];
+ ep = (env_t *) ((char*)loader_addr + off + 8);
+ calc_crc = the_env_crc32(0, ep->data, rdlen - 4);
+ if( ep->crc == calc_crc ) {
+ break;
+ } else {
+ continue;
+ }
+ }
+ }
+
+ /* Set runtime env variables based on loader's env */
+ if( off < (loff_t)env_boot_magic_search_size() ) {
+
+ /* read IMAGE variable */
+ sprintf(cmd, "env import %lx - IMAGE", (char*)ep);
+ run_command(cmd, 0);
+
+ /* Verify */
+ if( env_get("IMAGE") == NULL ) {
+ printf("ERROR! Failed to import IMAGE parameter from loader!\n");
+ return ret;
+ }
+
+ /* read default_partitions */
+ if( ( strcasecmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+ sprintf(cmd, "env import %lx - default_partitions", (char*)ep);
+ run_command(cmd, 0);
+
+ /* Verify */
+ if( env_get("default_partitions") == NULL ) {
+ printf("ERROR! Failed to import default_partitions parameter from loader!\n");
+ return ret;
+ }
+ }
+
+ /* Call partition init code */
+ printf("INFO: flash partition config updated. Repartitioning flash!\n");
+ ret = board_init_flash_parts(1);
+ } else {
+ printf("ERROR!: No environment found in loader binary!\n");
+ }
+ return ret;
+}
+
+int flash_upgrade_img_bundle( ulong bundle_addr , int img_index, const char * conf_name)
+{
+ char path[128];
+ ulong addr=0;
+ ulong size=0;
+ ulong loader_addr=0;
+ ulong loader_size=0;
+ int i=0;
+ int err = 0;
+ const char * bin_name;
+ const char * loader_bin_name;
+ const char * compat_str;
+ char *compat_copy;
+ int nodeoffset = 0;
+ int conf_nodeoffset = 0;
+ int max_entries = sizeof(fn_table)/sizeof(flashfn_table_entry);
+ int len;
+
+ /* verify hashes of all upgrade bundle contents */
+ if( fit_all_image_verify((void *)bundle_addr) ) {
+
+ /* Get offset of config node */
+ sprintf(path, "/configurations");
+ nodeoffset = fdt_path_offset((void *)bundle_addr, path);
+ if( nodeoffset < 0 ) {
+ printf("ERROR: %s node not found in bundle!\n", path);
+ return CMD_RET_FAILURE;
+ }
+
+ /* If configuration is specifed then use it */
+ if( !conf_name ) {
+ /* Get name of the default configuration */
+ conf_name = fdt_getprop((void *)bundle_addr, nodeoffset, "default", &len);
+ if( !conf_name ) {
+ printf("ERROR: Default configuration not found in bundle!\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+
+ /* Get offset of selected configurations fit node */
+ sprintf(path, "%s/%s", path, conf_name);
+ conf_nodeoffset = fdt_path_offset((void *)bundle_addr, path);
+ if( conf_nodeoffset < 0 ) {
+ printf("ERROR: %s node not found in bundle!\n", conf_name);
+ return CMD_RET_FAILURE;
+ }
+
+ /* Verify compatibility */
+ compat_str = fdt_getprop( (void *)bundle_addr, conf_nodeoffset, "compatible", &len);
+ if( !compat_str ) {
+ printf("Error: 'compatible' node not found in bundle!\n");
+ return CMD_RET_FAILURE;
+ }
+
+ compat_copy = malloc(strlen(compat_str)+1);
+ if(!compat_copy)
+ {
+ printf("Error allocating memory for compatibility string!\n");
+ return CMD_RET_FAILURE;
+ }
+ strcpy(compat_copy, compat_str);
+
+ if( verify_compat_string(compat_copy) ) {
+ printf("Error: Bundle is not compatible with platform!\n");
+ free(compat_copy);
+ return CMD_RET_FAILURE;
+ }
+ free(compat_copy);
+
+ /* Decide whether we want to reformat partitions based on loader
+ * binaries partition configuration configuration */
+ if( NULL == env_get("IMAGE") ) {
+ printf("WARNING: IMAGE env variable missing! Using IMAGE from loader binary!\n");
+ if( get_binary_from_bundle(bundle_addr, conf_name, "loader",
+ &loader_bin_name, &loader_addr, &loader_size) == 0 ) {
+ printf("INFO: Reformatting flash media based on new loader binary\n");
+ if( update_flash_parts_from_loader_bin( loader_addr, loader_size ) ) {
+ printf("ERROR: Failed to reformat flash based loader binary!\n");
+ return CMD_RET_FAILURE;
+ }
+
+ /* Set flag to prevent sync of run-time env to loader bin */
+ disable_runtime_env_sync = 1;
+ } else {
+ printf("ERROR! No loader binary AND IMAGE parameter not set!\n");
+ return CMD_RET_FAILURE;
+ }
+ } else if (env_get_hex("reformatOnUpgrade", 0)) {
+ printf("INFO: Reformatting partitions because reformatOnUpgrade == 1!\n");
+ err = board_init_flash_parts(1);
+ env_set("reformatOnUpgrade", NULL);
+ }
+
+ for( i=0; i<max_entries && !err; i++ ) {
+ /* Parse loader only if it has not been parsed before */
+ if( (strcmp(fn_table[i].name,"loader") == 0 ) && loader_addr && loader_size ) {
+ bin_name = loader_bin_name;
+ size = loader_size;
+ addr = loader_addr;
+ } else {
+ if (get_binary_from_bundle( bundle_addr, conf_name, fn_table[i].name,
+ &bin_name, &addr, &size ) ) {
+ continue;
+ }
+ }
+
+ /* Calling flashing function */
+ printf("Flashing %s (%s: 0x%lx bytes from 0x%lx) to %s%d.....\n",
+ fn_table[i].name, bin_name, size, addr, fn_table[i].name,
+ (strcmp(fn_table[i].name,"loader")?img_index:0));
+ err = fn_table[i].func(addr, size, img_index);
+ }
+
+ /* Reset flag */
+ disable_runtime_env_sync = 0;
+ } else {
+ err = CMD_RET_FAILURE;
+ }
+
+ return err;
+}
+
+static int do_flash_upgrade_img (cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ char cmd[128];
+ ulong bundle_addr=0;
+ int err = CMD_RET_FAILURE;
+ const char * conf_name = NULL;
+ int img_index = 0;
+ bool download = true;
+ bool commit = true;
+ int active_img_idx = get_active_img_idx();
+
+ /* Parse and remove the optional skip argument */
+ if ( argc > 1) {
+ if ( !strcmp(argv[1], "-s")) {
+ download = false;
+ argc--;
+ argv++;
+ } else if ( !strcmp(argv[1], "-i")) {
+ commit = false;
+ argc--;
+ argv++;
+ }
+ }
+
+ if( argc == 2 ) {
+ img_index = get_img_index_for_upgrade(0);
+ } else if( argc > 2 ) {
+ if( strlen(argv[2]) == 1 )
+ img_index = *argv[2] - '0';
+ else {
+ conf_name = argv[2];
+ img_index = get_img_index_for_upgrade(0);
+ }
+
+ if( argc > 3 ) {
+ conf_name = argv[3];
+ }
+ }
+
+ if( img_index < MIN_IMG_INDEX || img_index > MAX_IMG_INDEX ) {
+ printf("ERROR: Invalid Image Index specified!\n");
+ return CMD_RET_USAGE;
+ }
+
+ if (download)
+ sprintf(cmd, "tftp %lx %s", load_addr, argv[1]);
+
+ if( !download || run_command(cmd, 0) == 0 ) {
+ bundle_addr = env_get_hex("fileaddr", 0);
+
+ if (bundle_addr)
+ /* Call main img flashing function */
+ err = flash_upgrade_img_bundle(bundle_addr, img_index, conf_name);
+ }
+
+ if(err) {
+ printf("ERROR: Image upgrade failed!!\n");
+ } else {
+ printf("INFO: Image upgrade successfull!!\n");
+ if( commit ) {
+ printf("INFO: Committing Image!!\n");
+ commit_image( img_index );
+
+ /* Handle bootstrap condition */
+ if( active_img_idx == ACTIVE_IMGIDX_BOOTSTRAP ) {
+ /* Now that we have a valid image flashed, change active image index */
+ set_active_img_idx(img_index);
+ }
+ } else {
+ printf("INFO: Not Committing Image!!\n");
+ }
+ }
+
+ return err;
+}
+
+static int do_restoredefault(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int ret = -1;
+ if( strcmp(get_image_media(), FLASH_DEV_STR_NAND) == 0 ) {
+#ifdef BCA_SDK_NAND_CMD
+ ret = nand_restoredefault();
+#endif
+ }
+
+ if( ret && ( strcmp(get_image_media(), FLASH_DEV_STR_EMMC) == 0 ) ) {
+#ifdef BCA_SDK_EMMC_CMD
+ ret = emmc_restoredefault();
+#endif
+ }
+
+ if( ret && ( strcmp(get_image_media(), FLASH_DEV_STR_SPINOR) == 0 ) ) {
+#ifdef BCA_SDK_SPINOR_CMD
+ ret = spinor_restoredefault();
+#endif
+ }
+
+ return ret;
+}
+
+static int do_metadata(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int ret = -1;
+ int committed = 0;
+ int valid[2] = {0,0};
+ int seq[2] = {-1,-1};
+ int status = get_metadata_val(&committed, valid, seq);
+
+ if (argc == 1) {
+ if (0 == status) {
+ printf("committed-img: %d valid-imgs: ", committed);
+ if( valid[0] )
+ printf("%d", valid[0]);
+ if( valid[1] )
+ printf("%d", valid[1]);
+ printf(", seq# img 1: %d, img2: %d\n\n", seq[0], seq[1]);
+ ret = 0;
+ } else {
+ printf("metadata parse error\n");
+ }
+ } else if (argc == 3) {
+ committed = atoi(argv[1]);
+ valid[0] = atoi(strtok(argv[2],","));
+ valid[1] = atoi(strtok(NULL,","));
+
+ if (0 != set_metadata_val(&committed, valid, seq)) {
+ printf("metadata parse error\n");
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+#if defined(CONFIG_BCM_BOOTSTATE)
+static int do_activate(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
+{
+ bcmbca_set_boot_reason(BCM_BOOT_REASON_ACTIVATE);
+ run_command("reset", 0);
+ return 0;
+}
+#endif
+
+static int do_force(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
+{
+ int ret = 0;
+ if( argc > 1 ) {
+ if( atoi(argv[1]) == 1 ) {
+ if( (argc == 4)
+ && ( ( strcasecmp(argv[2], FLASH_DEV_STR_NAND) == 0 )
+ || ( strcasecmp(argv[2], FLASH_DEV_STR_SPINOR) == 0 )
+ || ( strcasecmp(argv[2], FLASH_DEV_STR_EMMC) == 0 ) )
+ && ( ( strcasecmp(argv[3], FLASH_DEV_STR_NAND) == 0 )
+ || ( strcasecmp(argv[3], FLASH_DEV_STR_SPINOR) == 0 )
+ || ( strcasecmp(argv[3], FLASH_DEV_STR_EMMC) == 0 ) ) ) {
+ forced_updates = 1;
+ strcpy(forced_boot_media,argv[2]);
+ strcpy(forced_image_media,argv[3]);
+ } else if(argc == 2) {
+ forced_updates = 1;
+ } else {
+ ret = CMD_RET_USAGE;
+ printf("Cannot determine boot/image flash type, please specify flash types!\n");
+ }
+ } else {
+ forced_updates = 0;
+ forced_boot_media[0] = '\0';
+ forced_image_media[0] = '\0';
+ }
+ }
+
+ printf("Forced Image Updates: %s, Forced flash types: Boot=%s, Image=%s\n",
+ (forced_updates?"Enabled":"Disabled"),
+ (forced_updates?forced_boot_media:"NOT SPECIFIED"),
+ (forced_updates?forced_image_media:"NOT SPECIFIED"));
+
+ return ret;
+}
+
+#ifdef CONFIG_BCMBCA_HTTPD
+static int do_httpd_start(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
+{
+ if(!httpd_check_net_env())
+ register_cli_job_cb(0, http_poll);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_BCMBCA_PMC
+static int do_bpcm_cmd(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int err = CMD_RET_USAGE;
+ int read = 0;
+ u32 addr, off, data;
+
+ if ((argc != 5) && (argc != 4))
+ return err;
+
+ if (!strcmp(argv[1], "r"))
+ read = 1;
+ else if (!strcmp(argv[1], "w"))
+ read = 0;
+ else
+ return err;
+
+ addr = atoi(argv[2]);
+ off = atoi(argv[3]);
+ if (!read) {
+ data = atoi(argv[4]);
+ err = WriteBPCMRegister(addr, off>>2, data);
+ printf("bpcm write data 0x%x to addr 0x%x offset 0x%x ret %d\n",
+ data, addr, off, err);
+ } else {
+ err = ReadBPCMRegister(addr, off>>2, &data);
+ printf("bpcm read data 0x%x from addr 0x%x offset 0x%x ret %d\n",
+ data, addr, off, err);
+ }
+
+
+ return err;
+}
+
+static int do_cpufreq(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int err = CMD_RET_USAGE, freqMHz;
+
+ if (argc != 2)
+ return err;
+
+ err = CMD_RET_SUCCESS;
+ freqMHz = atoi(argv[1]);
+ freqMHz = set_cpu_freq(freqMHz);
+ if (freqMHz > 0)
+ printf("cpu freq set to %dMHz\n", freqMHz);
+ else
+ err = CMD_RET_FAILURE;
+
+ return err;
+}
+#endif
+
+static int do_dev_spec_key(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int err = CMD_RET_USAGE;
+ int rc, len;
+ u32 dev_spec_key[8];
+ int i;
+ bool force = false;
+
+ if ( (argc == 2) && (strcmp(argv[1], "get") == 0)) {
+ rc = bcm_sec_get_dev_spec_key((char*)dev_spec_key, sizeof(u32)*8);
+ } else if ( (argc >= 10) && (strcmp(argv[1], "set") == 0)) {
+ /* Parse and remove the optional FORCE argument */
+ if( argc > 10 ) {
+ if ( !strcasecmp(argv[2], "-f")) {
+ force = true;
+ argc--;
+ argv++;
+ }
+ }
+
+ for(i=0; i<8; i++) {
+ dev_spec_key[i] = simple_strtoul(argv[i+2],NULL, 0);
+ }
+ if ( !force ) {
+ printf("WARNING: You are attempting to set a new device specific key.\n");
+ len = cli_readline("This operation cannot be undone, enter 'Y' to continue: ");
+ if( !len || console_buffer[0] != 'Y' ) {
+ printf("Device specific key setting aborted.\n");
+ return CMD_RET_SUCCESS;
+ }
+ }
+ rc = bcm_sec_set_dev_spec_key((char*)dev_spec_key, sizeof(u32)*8);
+ } else {
+ return err;
+ }
+
+ if (rc == 0) {
+ printf("Current Device Specific Key:\n");
+ for( i=0; i<8; i++ ) {
+ printf(" [%d]0x%08x\n", i, dev_spec_key[i]);
+ }
+ printf("\n\n");
+ err = CMD_RET_SUCCESS;
+ } else {
+ err = CMD_RET_FAILURE;
+ }
+
+ return err;
+}
+
+static int do_sec_ser_num(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int err = CMD_RET_USAGE;
+ int rc, len;
+ u32 sec_ser_num[8] = {0};
+ char * sec_ser_num_ptr = (char*)&sec_ser_num[0];
+ char * sec_ser_num_char_array;
+ char byte_buf[3] = {0};
+ int i,j;
+ bool force = false;
+ bool is_set = false;
+ bool is_odd = false;
+
+ if ( (argc == 2) && (strcmp(argv[1], "get") == 0)) {
+ rc = bcm_sec_get_sec_ser_num((char*)sec_ser_num, sizeof(u32)*8);
+ } else if ( (argc >= 3) && (strcmp(argv[1], "set") == 0)) {
+ is_set = true;
+ /* Parse and remove the optional FORCE argument */
+ if( argc == 4 ) {
+ if ( !strcasecmp(argv[2], "-f")) {
+ force = true;
+ argc--;
+ argv++;
+ }
+ }
+
+ /* Check if byte array exceeds 32 bytes OR contains an ODD number of characters */
+ sec_ser_num_char_array = argv[2];
+
+ /* Skip leading 0x if present */
+ if( sec_ser_num_char_array[1] == 'x' || sec_ser_num_char_array[1] == 'X' )
+ sec_ser_num_char_array += 2;
+
+ debug("sernum:%s len:%d\n", sec_ser_num_char_array, (int)strlen(sec_ser_num_char_array));
+ if( ((strlen(sec_ser_num_char_array)/2) > sizeof(sec_ser_num)) || (strlen(sec_ser_num_char_array) % 2)){
+ return CMD_RET_USAGE;
+ }
+
+ /* Check if there is an odd number of digits so that we can insert an extra zero */
+ if( strlen(sec_ser_num_char_array) % 2 )
+ is_odd = 1;
+
+ for(i=0,j=sizeof(sec_ser_num)-strlen(sec_ser_num_char_array)/2;
+ i<strlen(sec_ser_num_char_array),j<sizeof(sec_ser_num); j++){
+ if( is_odd && (i == 0) ) {
+ byte_buf[1] = sec_ser_num_char_array[i];
+ is_odd = false;
+ i++;
+ } else {
+ memcpy(byte_buf,&sec_ser_num_char_array[i], 2);
+ i += 2;
+ }
+
+ sec_ser_num_ptr[j] = simple_strtoul(byte_buf,NULL,16);
+ debug("byte_buf: %s 0x%02x\n", byte_buf, sec_ser_num_ptr[j]);
+ }
+
+ if ( !force ) {
+ printf("WARNING: You are attempting to set a new secure serial number.\n");
+ len = cli_readline("This operation cannot be undone, enter 'Y' to continue: ");
+ if( !len || console_buffer[0] != 'Y' ) {
+ printf("secure serial number setting aborted.\n");
+ return CMD_RET_SUCCESS;
+ }
+ }
+ rc = bcm_sec_set_sec_ser_num((char*)sec_ser_num, sizeof(u32)*8);
+ } else {
+ return err;
+ }
+
+ if (rc == 0) {
+ if( is_set )
+ printf("Set Secure Serial Number as:\n");
+ else
+ printf("Current Secure Serial Number:\n");
+
+ printf(" [");
+ for( i=0; i<sizeof(sec_ser_num); i++ ) {
+ printf("%02x", sec_ser_num_ptr[i]);
+ }
+ printf("]\n");
+
+ printf("In memory represenation:\n");
+ for( i=0; i<8; i++ ) {
+ printf(" [%d]0x%08x\n", i, sec_ser_num[i]);
+ }
+ printf("\n\n");
+ err = CMD_RET_SUCCESS;
+ } else {
+ err = CMD_RET_FAILURE;
+ }
+
+ return err;
+}
+static int do_antirollback(cmd_tbl_t * cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int err = CMD_RET_USAGE;
+ int rc, len;
+ u32 lvl;
+ bool force = false;
+
+
+ if ( (argc == 2) && (strcmp(argv[1], "get") == 0)) {
+ rc = bcm_sec_get_antirollback_lvl(&lvl);
+ } else if ( (argc >= 3) && (strcmp(argv[1], "set") == 0)) {
+ /* Parse and remove the optional FORCE argument */
+ if( argc > 3 ) {
+ if ( !strcasecmp(argv[2], "-f")) {
+ force = true;
+ argc--;
+ argv++;
+ }
+ }
+
+ /* get level */
+ lvl = atoi(argv[2]);
+ if ( !force ) {
+ printf("WARNING: You are attempting to set a new anti-rollback level.\n");
+ len = cli_readline("This operation cannot be undone, enter 'Y' to continue: ");
+ if( !len || console_buffer[0] != 'Y' ) {
+ printf("Anti-rollback level setting aborted.\n");
+ return CMD_RET_SUCCESS;
+ }
+ }
+ rc = bcm_sec_set_antirollback_lvl(lvl);
+ } else {
+ return err;
+ }
+
+ if (rc == 0) {
+ printf("Current anti-rollback level set to: %d\n", lvl);
+ err = CMD_RET_SUCCESS;
+ } else {
+ err = CMD_RET_FAILURE;
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_BCMBCA_XRDP_ETH
+extern int bcmbca_xrdp_eth_phy_status(void);
+extern int bcmbca_xrdp_eth_mac_status(void);
+extern int bcmbca_xrdp_eth_active_port_get(void);
+extern int bcmbca_xrdp_eth_active_port_set(int port);
+extern int bcmbca_xrdp_eth_env_active_port_set(int port);
+
+static int do_eth_active_port(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
+{
+ int port;
+
+ if (argc == 2)
+ {
+ port = (atoi(argv[1]));
+ bcmbca_xrdp_eth_active_port_set(port);
+ }
+
+ port = bcmbca_xrdp_eth_active_port_get();
+ printf("XRDP Ethernet active port is set to %d\n" ,port);
+
+ return 0;
+}
+
+static int on_active_port(const char *name, const char *value, enum env_op op, int flags)
+{
+ int active_port = -1;
+
+ if ((flags & H_INTERACTIVE) == 0)
+ return 0;
+
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ active_port = simple_strtoul(value, NULL, 10);
+ break;
+ case env_op_delete:
+ break;
+ default:
+ break;
+ }
+
+ return bcmbca_xrdp_eth_env_active_port_set(active_port);
+}
+U_BOOT_ENV_CALLBACK(active_port, on_active_port);
+#endif
+
+static char usage[] =
+#ifdef BCA_SDK_EMMC_CMD
+ "\n## eMMC Specific Test Commands ##\n"
+ "gpt_fixup\n"
+ " - Create GPT partitions if partition sizes are specfied via special uboot\n"
+ " - environment variables. The env variable name has to be in the format:\n"
+ " - <partition_name>_vol_size=<size in MiB>\n"
+#endif /* BCA_SDK_EMMC_CMD */
+#ifdef BCA_SDK_SPINOR_CMD
+ "\n## SPINOR Specific Test Commands ##\n"
+ "flash_spinor_fit\n"
+ " - Download and flash atf+uboot+vmlinux+dtb in brcm_full.itb to SPI NOR flash \n"
+ "flash_spinor_rootfs\n"
+ " - Download and flash rootfs in rootfs.squashfs to SPI NOR flash\n"
+ "flash_spinor_upgrade [-s] <filename> [conf]\n"
+ "flash_spinor_upgrade <filename> [<img> [<conf>]]\n"
+ " - Download and flash an image upgrade bundle to SPI NOR flash\n"
+ "flash_spinor_binary <filename> \n"
+ " - Erase whole flash,download and flash a binary image to SPI NOR flash start from 0\n"
+ "boot_spinor [boardid]\n"
+ " - Boot linux from image in SPI NOR flash.\n"
+#endif
+ "\n## Generic Test Commands ##\n"
+ "force \n"
+ " - Without arguments, display if forced image updates are enabled\n"
+ "force [force value] <[Boot Flash Type] [Image Flash Type]>\n"
+ " - Enable(value=1)/Disable(value=0) forced image updates. All compatibility checks are ignored if enabled\n"
+ " - If boot and image flash types are not detected, then they need to be specified as 2nd and 3rd args\n"
+ " - Valid flash type values = [NAND|SPINAND|EMMC|NOR]\n"
+ "restoredefault\n"
+ " - Delete contents of /data so that it gets populated with default values\n"
+ "flash_loader\n"
+ " - Download and flash SPL+TPL in loader_test_<flash>_<chip>.bin to boot flash\n"
+#if defined(BCA_SDK_NAND_CMD) || defined(BCA_SDK_EMMC_CMD)
+ "flash_bootfs_raw <bootfs binary> [img]\n"
+ "flash_rootfs_raw <rootfs binary> [img]\n"
+ " - Download and flash raw bootfs/rootfs binary to flash \n"
+ " - WARNING: These are raw writes with no content, security or compatibility checks. Metadata is NOT updated \n"
+ "metadata \n"
+ "metadata [committed] [valid],[valid]\n"
+ " - without arguments, parse and display metadata\n"
+ " - set metadata values (example \"metadata 1 1,2\" for both images valid and #1 committed)\n"
+ " - NOTE: Must do a sw reset for metadata changes to take affect\n"
+#endif
+ "flash_img_upgrade [-s] <filename> [conf]\n"
+ "flash_img_upgrade [-i] <filename> [<img> [<conf>]]\n"
+ " - Download and flash an image upgrade bundle via TFTP\n"
+ " - NOTE: Must do a sw reset to use the new image\n"
+ "load_img [boardid]\n"
+ "load_img [<img> [<boardid>]]\n"
+ " - Load image from flash into DDR.\n"
+ "boot_img [boardid]\n"
+ "boot_img [<img> [<boardid>]]\n"
+ " - Boot linux from image in flash.\n"
+ "[Legend - Optional Parameters]\n"
+ " -s: Skip downloading the image via tftp. Assume it is already at ${fileaddr}\n"
+ " -i: Inactive. Do not change activation state of new image i.e do not commit image\n"
+ " img: Image index for flashing/booting. Valid values: [1|2]. Default index is determined from metadata\n"
+ " fstype: Filesystem type for flashing. Valid values: [squashfs|ubifs|ext4]. Default is squashfs\n"
+ " boardid: Boardid to determine boot configuration. If omitted default configuration node is used\n"
+ " conf: Configuration name used for flashing img bundle. If omitted default configuration node is used\n\n"
+#ifdef CONFIG_BCMBCA_HTTPD
+ "httpd_start \n"
+ " - without arguments, start httpd server\n"
+#endif
+#ifdef CONFIG_BCMBCA_PMC
+ "bpcm_cmd <r|w> <addr> <offset> [<data>]\n"
+ " - read/write bpcm register\n"
+ "cpufreq <freq in MHz>\n"
+ " - set cpu frequency\n"
+#endif
+ "antirollback get\n"
+ " - get current anti-rollback level\n"
+ "antirollback set [-f] <new anti-rollback level to set>\n"
+ " - set new anti-rollback level. [-f] will force the commit and skip warnings\n"
+ "sec_ser_num get \n"
+ " - get current secure serial number level ( 64 digits )\n"
+ "sec_ser_num set [-f] < Hex secure serial number ( Max 64 digits )>\n"
+ " - set new secure serial number . [-f] will force the commit and skip warnings\n"
+ "dev_spec_key get \n"
+ " - get current device specific key ( 32 bytes )\n"
+ "dev_spec_key set [-f] <32-bit hex word 0>...<32-bit hex word 7> \n"
+ " - set new device specific key. [-f] will force the commit and skip warnings\n"
+ ;
+
+static char sdk_usage[] =
+ "\nforce\n"
+ " - Without arguments, display if forced image updates are enabled\n"
+ "force [force value] <[Boot Flash Type] [Image Flash Type]>\n"
+ " - Enable(value=1)/Disable(value=0) forced image updates. All compatibility checks are ignored if enabled\n"
+ " - If boot and image flash types are not detected, then they need to be specified as 2nd and 3rd args\n"
+ " - Valid flash type values = [NAND|SPINAND|EMMC|NOR]\n"
+ "restoredefault\n"
+ " - Delete contents of /data so that it gets populated with default values\n"
+#if defined(BCA_SDK_NAND_CMD) || defined(BCA_SDK_EMMC_CMD)
+ "metadata \n"
+ "metadata [committed] [valid],[valid]\n"
+ " - without arguments, parse and display metadata\n"
+ " - set metadata values (example \"metadata 1 1,2\" for both images valid and #1 committed)\n"
+ " - NOTE: Must do a sw reset for metadata changes to take affect\n"
+#endif
+ "flash_img_upgrade [-s] <filename> [conf]\n"
+ "flash_img_upgrade [-i] <filename> [<img> [<conf>]]\n"
+ " - Download and flash an image upgrade bundle via TFTP\n"
+ " - NOTE: Must do a sw reset to use the new image\n"
+ "load_img [boardid]\n"
+ "load_img [<img> [<boardid>]]\n"
+ " - Load image from flash into DDR.\n"
+ "boot_img [boardid]\n"
+ "boot_img [<img> [<boardid>]]\n"
+ " - Boot linux from image in flash.\n"
+ "[Legend - Optional Parameters]\n"
+ " -s: Skip downloading the image via tftp. Assume it is already at ${fileaddr}\n"
+ " -i: Inactive. Mark new image as inactive i.e do not commit image\n"
+ " img: Image index for flashing/booting. Valid values: [1|2]. Default index is determined from metadata\n"
+ " boardid: Boardid to determine boot configuration. If omitted default configuration node is used\n"
+ " conf: Configuration name used for flashing img bundle. If omitted default configuration node is used\n\n"
+#ifdef CONFIG_BCMBCA_HTTPD
+ "httpd_start \n"
+ " - without arguments, start httpd server\n"
+#endif
+#ifdef CONFIG_BCMBCA_XRDP_ETH
+ "active_port [port]\n"
+ " - Set the active network driver's port to send packets from\n"
+ " - without arguments, display the current active port\n"
+ "eth_status [type]\n"
+ " - Print the XRDP Ethernet network driver status tables\n"
+ " - Argument can be phy or mac. If no argument provided, both tables will be printed\n"
+#endif
+ ;
+
+U_BOOT_CMD_WITH_SUBCMDS(bca_test, "Broadcom test commands", usage,
+ U_BOOT_SUBCMD_MKENT(flash_loader, 1, 0, do_flash_loader),
+#ifdef BCA_SDK_EMMC_CMD
+ U_BOOT_SUBCMD_MKENT(gpt_fixup, 1, 0, do_gpt_fixup),
+#endif /* BCA_SDK_EMMC_CMD */
+#ifdef BCA_SDK_SPINOR_CMD
+ U_BOOT_SUBCMD_MKENT(flash_spinor_fit, 1, 0, do_flash_spinor_bootfs_rootfs),
+ U_BOOT_SUBCMD_MKENT(flash_spinor_rootfs, 1, 0, do_flash_spinor_bootfs_rootfs),
+ U_BOOT_SUBCMD_MKENT(flash_spinor_upgrade, 5, 0, do_flash_upgrade_img),
+ U_BOOT_SUBCMD_MKENT(flash_spinor_binary, 2, 0, do_flash_spinor_binary),
+ U_BOOT_SUBCMD_MKENT(boot_spinor, 3, 0, do_boot),
+#endif
+#if defined(CONFIG_BCM_BOOTSTATE)
+ U_BOOT_SUBCMD_MKENT(activate, 1, 0, do_activate),
+#endif /* CONFIG_BCM_BOOTSTATE */
+ U_BOOT_SUBCMD_MKENT(force, 4, 0, do_force),
+ U_BOOT_SUBCMD_MKENT(restoredefault, 1, 0, do_restoredefault),
+#if defined(BCA_SDK_NAND_CMD) || defined(BCA_SDK_EMMC_CMD)
+ U_BOOT_SUBCMD_MKENT(flash_bootfs_raw, 3, 0, do_flash_bins),
+ U_BOOT_SUBCMD_MKENT(flash_rootfs_raw, 3, 0, do_flash_bins),
+ U_BOOT_SUBCMD_MKENT(metadata, 5, 0, do_metadata),
+#endif
+ U_BOOT_SUBCMD_MKENT(flash_img_upgrade, 5, 0, do_flash_upgrade_img),
+ U_BOOT_SUBCMD_MKENT(boot_img, 3, 0, do_boot)
+#ifdef CONFIG_BCMBCA_HTTPD
+ ,U_BOOT_SUBCMD_MKENT(httpd_start, 1, 0, do_httpd_start)
+#endif
+#ifdef CONFIG_BCMBCA_PMC
+ ,U_BOOT_SUBCMD_MKENT(bpcm_cmd, 5, 0, do_bpcm_cmd)
+ ,U_BOOT_SUBCMD_MKENT(cpufreq, 2, 0, do_cpufreq)
+#endif
+ ,U_BOOT_SUBCMD_MKENT(antirollback, 4, 0, do_antirollback)
+ ,U_BOOT_SUBCMD_MKENT(sec_ser_num, 12, 0, do_sec_ser_num)
+ ,U_BOOT_SUBCMD_MKENT(dev_spec_key, 12, 0, do_dev_spec_key)
+ );
+
+U_BOOT_CMD_WITH_SUBCMDS(sdk, "Broadcom SDK support commands", sdk_usage,
+ U_BOOT_SUBCMD_MKENT(force, 4, 0, do_force),
+ U_BOOT_SUBCMD_MKENT(restoredefault, 1, 0, do_restoredefault),
+#if defined(BCA_SDK_NAND_CMD) || defined(BCA_SDK_EMMC_CMD)
+ U_BOOT_SUBCMD_MKENT(metadata, 5, 0, do_metadata),
+#endif
+ U_BOOT_SUBCMD_MKENT(flash_img_upgrade, 5, 0, do_flash_upgrade_img),
+ U_BOOT_SUBCMD_MKENT(boot_img, 3, 0, do_boot),
+ U_BOOT_SUBCMD_MKENT(load_img, 3, 0, do_load)
+#ifdef CONFIG_BCMBCA_HTTPD
+ ,U_BOOT_SUBCMD_MKENT(httpd_start, 1, 0, do_httpd_start)
+#endif
+#ifdef CONFIG_BCMBCA_XRDP_ETH
+ ,U_BOOT_SUBCMD_MKENT(active_port, 2, 0, do_eth_active_port)
+#endif
+ );
+