int setup_waveform_file(ulong waveform_buf) { char *fs_argv[5]; char addr[17]; ulong file_len, mmc_dev; if (!check_mmc_autodetect()) mmc_dev = getenv_ulong("mmcdev", 10, 0); else mmc_dev = mmc_get_env_devno(); sprintf(addr, "%lx", waveform_buf); fs_argv[0] = "fatload"; fs_argv[1] = "mmc"; fs_argv[2] = simple_itoa(mmc_dev); fs_argv[3] = addr; fs_argv[4] = getenv("epdc_waveform"); if (!fs_argv[4]) fs_argv[4] = "epdc_splash.bin"; if (do_fat_fsload(NULL, 0, 5, fs_argv)) { printf("MMC Device %lu not found\n", mmc_dev); return -1; } file_len = getenv_hex("filesize", 0); if (!file_len) return -1; flush_cache((ulong)addr, file_len); return 0; }
int do_bootloader_validate(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { uint32_t image_addr = 0; const bootloader_header_t *header; if (argc >= 2) image_addr = simple_strtoul(argv[1], NULL, 16); if (!image_addr) { image_addr = getenv_hex("fileaddr", load_addr); if (!image_addr) { puts("ERROR: Unable to get image address from " "'fileaddr' environment variable\n"); return 1; } } header = (void *)image_addr; if (validate_header(header)) { puts("Image does not have valid header\n"); return 1; } if (validate_data(header)) return 1; printf("Image validated. Header size %d, data size %d\n", header->hlen, header->dlen); printf(" Header crc 0x%x, data crc 0x%x\n", header->hcrc, header->dcrc); printf(" Image link address is 0x%llx\n", header->address); return 0; }
/* * Flattened Device Tree command, see the help for parameter definitions. */ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) return CMD_RET_USAGE; /* * Set the address of the fdt */ if (strncmp(argv[1], "ad", 2) == 0) { unsigned long addr; int control = 0; struct fdt_header *blob; /* * Set the address [and length] of the fdt. */ argc -= 2; argv += 2; /* Temporary #ifdef - some archs don't have fdt_blob yet */ #ifdef CONFIG_OF_CONTROL if (argc && !strcmp(*argv, "-c")) { control = 1; argc--; argv++; } #endif if (argc == 0) { if (control) blob = (struct fdt_header *)gd->fdt_blob; else blob = working_fdt; if (!blob || !fdt_valid(&blob)) return 1; printf("The address of the fdt is %#08lx\n", control ? (ulong)map_to_sysmem(blob) : getenv_hex("fdtaddr", 0)); return 0; } addr = simple_strtoul(argv[0], NULL, 16); blob = map_sysmem(addr, 0); if (!fdt_valid(&blob)) return 1; if (control) gd->fdt_blob = blob; else set_working_fdt_addr(addr); if (argc >= 2) { int len; int err; /* * Optional new length */ len = simple_strtoul(argv[1], NULL, 16); if (len < fdt_totalsize(blob)) { printf ("New length %d < existing length %d, " "ignoring.\n", len, fdt_totalsize(blob)); } else { /* * Open in place with a new length. */ err = fdt_open_into(blob, blob, len); if (err != 0) { printf ("libfdt fdt_open_into(): %s\n", fdt_strerror(err)); } } } return CMD_RET_SUCCESS; } if (!working_fdt) { puts( "No FDT memory address configured. Please configure\n" "the FDT address via \"fdt addr <address>\" command.\n" "Aborting!\n"); return CMD_RET_FAILURE; } /* * Move the working_fdt */ if (strncmp(argv[1], "mo", 2) == 0) { struct fdt_header *newaddr; int len; int err; if (argc < 4) return CMD_RET_USAGE; /* * Set the address and length of the fdt. */ working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); if (!fdt_valid(&working_fdt)) return 1; newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16); /* * If the user specifies a length, use that. Otherwise use the * current length. */ if (argc <= 4) { len = fdt_totalsize(working_fdt); } else { len = simple_strtoul(argv[4], NULL, 16); if (len < fdt_totalsize(working_fdt)) { printf ("New length 0x%X < existing length " "0x%X, aborting.\n", len, fdt_totalsize(working_fdt)); return 1; } } /* * Copy to the new location. */ err = fdt_open_into(working_fdt, newaddr, len); if (err != 0) { printf ("libfdt fdt_open_into(): %s\n", fdt_strerror(err)); return 1; } working_fdt = newaddr; /* * Make a new node */ } else if (strncmp(argv[1], "mk", 2) == 0) { char *pathp; /* path */ char *nodep; /* new node to add */ int nodeoffset; /* node offset from libfdt */ int err; /* * Parameters: Node path, new node to be appended to the path. */ if (argc < 4) return CMD_RET_USAGE; pathp = argv[2]; nodep = argv[3]; nodeoffset = fdt_path_offset (working_fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } err = fdt_add_subnode(working_fdt, nodeoffset, nodep); if (err < 0) { printf ("libfdt fdt_add_subnode(): %s\n", fdt_strerror(err)); return 1; } /* * Set the value of a property in the working_fdt. */ } else if (argv[1][0] == 's') { char *pathp; /* path */ char *prop; /* property */ int nodeoffset; /* node offset from libfdt */ static char data[SCRATCHPAD]; /* storage for the property */ int len; /* new length of the property */ int ret; /* return value */ /* * Parameters: Node path, property, optional value. */ if (argc < 4) return CMD_RET_USAGE; pathp = argv[2]; prop = argv[3]; if (argc == 4) { len = 0; } else { ret = fdt_parse_prop(&argv[4], argc - 4, data, &len); if (ret != 0) return ret; } nodeoffset = fdt_path_offset (working_fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len); if (ret < 0) { printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret)); return 1; } /******************************************************************** * Get the value of a property in the working_fdt. ********************************************************************/ } else if (argv[1][0] == 'g') { char *subcmd; /* sub-command */ char *pathp; /* path */ char *prop; /* property */ char *var; /* variable to store result */ int nodeoffset; /* node offset from libfdt */ const void *nodep; /* property node pointer */ int len = 0; /* new length of the property */ /* * Parameters: Node path, property, optional value. */ if (argc < 5) return CMD_RET_USAGE; subcmd = argv[2]; if (argc < 6 && subcmd[0] != 's') return CMD_RET_USAGE; var = argv[3]; pathp = argv[4]; prop = argv[5]; nodeoffset = fdt_path_offset(working_fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { int reqIndex = -1; int startDepth = fdt_node_depth( working_fdt, nodeoffset); int curDepth = startDepth; int curIndex = -1; int nextNodeOffset = fdt_next_node( working_fdt, nodeoffset, &curDepth); if (subcmd[0] == 'n') reqIndex = simple_strtoul(argv[5], NULL, 16); while (curDepth > startDepth) { if (curDepth == startDepth + 1) curIndex++; if (subcmd[0] == 'n' && curIndex == reqIndex) { const char *nodeName = fdt_get_name( working_fdt, nextNodeOffset, NULL); setenv(var, (char *)nodeName); return 0; } nextNodeOffset = fdt_next_node( working_fdt, nextNodeOffset, &curDepth); if (nextNodeOffset < 0) break; } if (subcmd[0] == 's') { /* get the num nodes at this level */ setenv_ulong(var, curIndex + 1); } else { /* node index not found */ printf("libfdt node not found\n"); return 1; } } else { nodep = fdt_getprop( working_fdt, nodeoffset, prop, &len); if (len == 0) { /* no property value */ setenv(var, ""); return 0; } else if (len > 0) { if (subcmd[0] == 'v') { int ret; ret = fdt_value_setenv(nodep, len, var); if (ret != 0) return ret; } else if (subcmd[0] == 'a') { /* Get address */ char buf[11]; sprintf(buf, "0x%p", nodep); setenv(var, buf); } else if (subcmd[0] == 's') { /* Get size */ char buf[11]; sprintf(buf, "0x%08X", len); setenv(var, buf); } else return CMD_RET_USAGE; return 0; } else { printf("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } } /* * Print (recursive) / List (single level) */ } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { int depth = MAX_LEVEL; /* how deep to print */ char *pathp; /* path */ char *prop; /* property */ int ret; /* return value */ static char root[2] = "/"; /* * list is an alias for print, but limited to 1 level */ if (argv[1][0] == 'l') { depth = 1; } /* * Get the starting path. The root node is an oddball, * the offset is zero and has no name. */ if (argc == 2) pathp = root; else pathp = argv[2]; if (argc > 3) prop = argv[3]; else prop = NULL; ret = fdt_print(pathp, prop, depth); if (ret != 0) return ret; /* * Remove a property/node */ } else if (strncmp(argv[1], "rm", 2) == 0) { int nodeoffset; /* node offset from libfdt */ int err; /* * Get the path. The root node is an oddball, the offset * is zero and has no name. */ nodeoffset = fdt_path_offset (working_fdt, argv[2]); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } /* * Do the delete. A fourth parameter means delete a property, * otherwise delete the node. */ if (argc > 3) { err = fdt_delprop(working_fdt, nodeoffset, argv[3]); if (err < 0) { printf("libfdt fdt_delprop(): %s\n", fdt_strerror(err)); return err; } } else { err = fdt_del_node(working_fdt, nodeoffset); if (err < 0) { printf("libfdt fdt_del_node(): %s\n", fdt_strerror(err)); return err; } } /* * Display header info */ } else if (argv[1][0] == 'h') { u32 version = fdt_version(working_fdt); printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt), fdt_totalsize(working_fdt)); printf("off_dt_struct:\t\t0x%x\n", fdt_off_dt_struct(working_fdt)); printf("off_dt_strings:\t\t0x%x\n", fdt_off_dt_strings(working_fdt)); printf("off_mem_rsvmap:\t\t0x%x\n", fdt_off_mem_rsvmap(working_fdt)); printf("version:\t\t%d\n", version); printf("last_comp_version:\t%d\n", fdt_last_comp_version(working_fdt)); if (version >= 2) printf("boot_cpuid_phys:\t0x%x\n", fdt_boot_cpuid_phys(working_fdt)); if (version >= 3) printf("size_dt_strings:\t0x%x\n", fdt_size_dt_strings(working_fdt)); if (version >= 17) printf("size_dt_struct:\t\t0x%x\n", fdt_size_dt_struct(working_fdt)); printf("number mem_rsv:\t\t0x%x\n", fdt_num_mem_rsv(working_fdt)); printf("\n"); /* * Set boot cpu id */ } else if (strncmp(argv[1], "boo", 3) == 0) { unsigned long tmp = simple_strtoul(argv[2], NULL, 16); fdt_set_boot_cpuid_phys(working_fdt, tmp); /* * memory command */ } else if (strncmp(argv[1], "me", 2) == 0) { uint64_t addr, size; int err; addr = simple_strtoull(argv[2], NULL, 16); size = simple_strtoull(argv[3], NULL, 16); err = fdt_fixup_memory(working_fdt, addr, size); if (err < 0) return err; /* * mem reserve commands */ } else if (strncmp(argv[1], "rs", 2) == 0) { if (argv[2][0] == 'p') { uint64_t addr, size; int total = fdt_num_mem_rsv(working_fdt); int j, err; printf("index\t\t start\t\t size\n"); printf("-------------------------------" "-----------------\n"); for (j = 0; j < total; j++) { err = fdt_get_mem_rsv(working_fdt, j, &addr, &size); if (err < 0) { printf("libfdt fdt_get_mem_rsv(): %s\n", fdt_strerror(err)); return err; } printf(" %x\t%08x%08x\t%08x%08x\n", j, (u32)(addr >> 32), (u32)(addr & 0xffffffff), (u32)(size >> 32), (u32)(size & 0xffffffff)); } } else if (argv[2][0] == 'a') {
/** * Command for updating a bootloader image in flash. This function * parses the arguments, and validates the header (if header exists.) * Actual flash updating is done by flash type specific functions. * * @return 0 on success * 1 on failure */ int do_bootloader_update(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { uint32_t image_addr = 0; uint32_t image_len = 0; uint32_t burn_addr = 0; int failsafe = 0; const bootloader_header_t *header; int force_nand = 0; int force_spi = 0; if (argc >= 2) { if (!strcmp(argv[1], "nand")) { debug("Forced NAND bootloader update\n"); force_nand = 1; argc--; argv++; } else if (!strcmp(argv[1], "spi")) { debug("Forced SPI bootloader update\n"); force_spi = 1; argc--; argv++; if (!strcmp(argv[1], "failsafe")) { failsafe = 1; argc--; argv++; } } } if (argc >= 2) image_addr = simple_strtoul(argv[1], NULL, 16); if (argc >= 3) image_len = simple_strtoul(argv[2], NULL, 16); if (argc >= 4) { if (force_spi || force_nand) { if (!strcmp("failsafe", argv[3])) failsafe = 1; } else { burn_addr = simple_strtoul(argv[3], NULL, 16); } } if ((argc >= 5) && (strcmp("failsafe", argv[4]) == 0)) failsafe = 1; /* If we don't support failsafe images, we need to put the image at the * base of flash, so we treat all images like failsafe image in this * case. */ #ifdef CONFIG_OCTEON_NO_FAILSAFE failsafe = 1; burn_addr = 0x1fc00000; #endif if (!burn_addr) burn_addr = getenv_hex("burnaddr", 0); if (!image_addr) { image_addr = getenv_hex("fileaddr", load_addr); if (!image_addr) { puts("ERROR: Unable to get image address from " "'fileaddr' environment variable\n"); return 1; } } DBGUPD("%s: burn address: 0x%x, image address: 0x%x\n", __func__, burn_addr, image_addr); /* Figure out what kind of flash we are going to update. This will * typically come from the bootloader header. If the bootloader does * not have a header, then it is assumed to be a legacy NOR image, and * a destination NOR flash address must be supplied. NAND images * _must_ have a header. */ header = (void *)image_addr; if (header->magic != BOOTLOADER_HEADER_MAGIC) { /* No header, assume headerless NOR bootloader image */ puts("No valid bootloader header found. Assuming old headerless image\n" "Image checks cannot be performed\n"); if (!burn_addr) { burn_addr = CONFIG_SYS_NORMAL_BOOTLOADER_BASE; DBGUPD("Unable to get burn address from 'burnaddr' environment variable,\n"); DBGUPD(" using default 0x%x\n", burn_addr); } /* We only need image length for the headerless case */ if (!image_len) { image_len = getenv_hex("filesize", 0); if (!image_len) { puts("ERROR: Unable to get image size from " "'filesize' environment variable\n"); return 1; } } return do_bootloader_update_nor(image_addr, image_len, burn_addr, failsafe); } /* We have a header, so validate image */ if (validate_header(header)) { puts("ERROR: Image header has invalid CRC.\n"); return 1; } if (validate_data(header)) /* Errors printed */ return 1; /* We now have a valid image, so determine what to do with it. */ puts("Valid bootloader image found.\n"); /* Check to see that it is for the board we are running on */ if (header->board_type != cvmx_sysinfo_get()->board_type) { printf("Current board type: %s (%d), image board type: %s (%d)\n", cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type), cvmx_sysinfo_get()->board_type, cvmx_board_type_to_string(header->board_type), header->board_type); if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_GENERIC && header->board_type != CVMX_BOARD_TYPE_GENERIC) { puts("ERROR: Bootloader image is not for this board type.\n"); return 1; } else { puts("Loading mismatched image since current " "or new bootloader is generic.\n"); } } /* SDK 1.9.0 NOR images have rev of 1.1 and unkown image_type */ if (((header->image_type == BL_HEADER_IMAGE_NOR) || (header->image_type == BL_HEADER_IMAGE_UNKNOWN && header->maj_rev == 1 && header->min_rev == 1)) && !force_nand && !force_spi) { debug("Updating NOR bootloader\n"); return do_bootloader_update_nor(image_addr, 0, burn_addr, failsafe); #if defined(CONFIG_CMD_OCTEON_NAND) || defined(CONFIG_OCTEON_NAND_BOOT_END) } else if (!force_spi && (header->image_type == BL_HEADER_IMAGE_STAGE2 || header->image_type == BL_HEADER_IMAGE_STAGE3 || force_nand)) { debug("Updating NAND bootloader\n"); return (do_bootloader_update_nand(image_addr)); #endif #if defined(CONFIG_OCTEON_SPI_BOOT_END) } else if (!force_nand && (header->image_type == BL_HEADER_IMAGE_STAGE2 || header->image_type == BL_HEADER_IMAGE_STAGE3 || force_spi)) { debug("Updating SPI bootloader\n"); return do_bootloader_update_spi(image_addr, header->dlen + header->hlen, failsafe, false); #else } else { puts("ERROR: This bootloader not compiled for this medium\n"); return 1; #endif } return 1; }