| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| |
| *******************************************************************************/ |
| |
| #include <config.h> |
| #include <common.h> |
| #include "mvCommon.h" |
| #include <command.h> |
| #include <net.h> |
| #include <environment.h> |
| |
| #if defined(MV_INCLUDE_USB) |
| #include <usb.h> |
| #endif |
| |
| #include <fs.h> |
| |
| #define DESTINATION_STRING 10 |
| |
| #if defined(CONFIG_CMD_NAND) |
| #include <nand.h> |
| extern nand_info_t nand_info[]; /* info for NAND chips */ |
| #endif |
| |
| #ifdef CONFIG_CMD_SF |
| #include <spi_flash.h> |
| extern struct spi_flash *flash; |
| #endif |
| |
| #ifdef CONFIG_CMD_FLASH |
| #include <flash.h> |
| extern flash_info_t flash_info[]; /* info for FLASH chips */ |
| #endif |
| |
| #if defined(MV_MMC_BOOT) |
| #include <mmc.h> |
| extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src); |
| #endif |
| |
| #if 0 /* def MV_NOR_BOOT */ |
| static unsigned int flash_in_which_sec(flash_info_t *fl,unsigned int offset) |
| { |
| unsigned int sec_num; |
| if(NULL == fl) |
| return 0xFFFFFFFF; |
| |
| for( sec_num = 0; sec_num < fl->sector_count ; sec_num++){ |
| /* If last sector*/ |
| if (sec_num == fl->sector_count -1) |
| { |
| if((offset >= fl->start[sec_num]) && |
| (offset <= (fl->size + fl->start[0] - 1)) ) |
| { |
| return sec_num; |
| } |
| |
| } |
| else |
| { |
| if((offset >= fl->start[sec_num]) && |
| (offset < fl->start[sec_num + 1]) ) |
| { |
| return sec_num; |
| } |
| |
| } |
| } |
| /* return illegal sector Number */ |
| return 0xFFFFFFFF; |
| |
| } |
| #endif /* !defined(MV_NOR_BOOT) */ |
| |
| #ifdef MV_INCLUDE_USB |
| /* |
| * Load u-boot bin file from usb device |
| * file_name is the name of u-boot file |
| */ |
| int load_from_usb(const char* file_name) |
| { |
| const char *addr_str; |
| unsigned long addr; |
| int filesize = 0; |
| |
| usb_stop(); |
| printf("(Re)start USB...\n"); |
| |
| if (usb_init() < 0) { |
| printf("usb_init failed\n"); |
| return 0; |
| } |
| |
| /* try to recognize storage devices immediately */ |
| if (-1 == usb_stor_scan(1)) { |
| printf("USB storage device not found\n"); |
| return 0; |
| } |
| |
| /* always load from usb 0 */ |
| if (fs_set_blk_dev("usb", "0", FS_TYPE_ANY)) |
| { |
| printf("USB 0 not found\n"); |
| return 0; |
| } |
| |
| addr_str = getenv("loadaddr"); |
| if (addr_str != NULL) |
| addr = simple_strtoul(addr_str, NULL, 16); |
| else |
| addr = CONFIG_SYS_LOAD_ADDR; |
| |
| filesize = fs_read(file_name, addr, 0, 0); |
| return filesize; |
| } |
| #endif |
| |
| /* |
| * Extract arguments from bubt command line |
| * argc, argv are the input arguments of bubt command line |
| * loadfrom is a pointer to the extracted argument: from where to load the u-boot bin file |
| * destination_burn is a pointer to a string which denotes the bubt interface |
| */ |
| MV_STATUS fetch_bubt_cmd_args(int argc, char * const argv[], int *loadfrom, char *destination_burn) |
| { |
| *loadfrom = 0; |
| strcpy(destination_burn,"default"); |
| /* bubt */ |
| if (argc < 2) { |
| copy_filename (BootFile, "u-boot.bin", sizeof(BootFile)); |
| printf("Using default filename \"u-boot.bin\" \n"); |
| } |
| /* "bubt filename" or "bubt destination"*/ |
| else if (argc == 2) { |
| if ((0 == strcmp(argv[1], "spi")) || (0 == strcmp(argv[1], "nand")) |
| || (0 == strcmp(argv[1], "nor"))) |
| { |
| strcpy(destination_burn, argv[1]); |
| copy_filename (BootFile, "u-boot.bin", sizeof(BootFile)); |
| printf("Using default filename \"u-boot.bin\" \n"); |
| } |
| else |
| { |
| copy_filename (BootFile, argv[1], sizeof(BootFile)); |
| } |
| } |
| /* "bubt filename destination" or "bubt destination source" */ |
| else if (argc == 3) { |
| if ((0 == strcmp(argv[1], "spi")) || (0 == strcmp(argv[1], "nand")) |
| || (0 == strcmp(argv[1], "nor"))) |
| { |
| strcpy(destination_burn, argv[1]); |
| copy_filename (BootFile, "u-boot.bin", sizeof(BootFile)); |
| printf("Using default filename \"u-boot.bin\" \n"); |
| |
| if (0 == strcmp("usb", argv[2])) { |
| #ifdef MV_INCLUDE_USB |
| *loadfrom = 1; |
| #else |
| printf("Error: USB is not supported on current machine\n"); |
| return MV_ERROR; |
| #endif |
| } |
| |
| } |
| else |
| { |
| strcpy(destination_burn, argv[2]); |
| |
| copy_filename (BootFile, argv[1], sizeof(BootFile)); |
| } |
| } |
| /* "bubt filename destination source" */ |
| else |
| { |
| strcpy(destination_burn, argv[2]); |
| |
| copy_filename (BootFile, argv[1], sizeof(BootFile)); |
| |
| if (0 == strcmp("usb", argv[3])) { |
| #ifdef MV_INCLUDE_USB |
| *loadfrom = 1; |
| #else |
| printf("Error: USB is not supported on current machine\n"); |
| return MV_ERROR; |
| #endif |
| } |
| } |
| return MV_OK; |
| } |
| |
| /* |
| * Load u-boot bin file into ram from external device: tftp, usb or other devices |
| * loadfrom specifies the source device: tftp, usb or other devices |
| * (currently only tftp and usb are supported ) |
| */ |
| int fetch_uboot_file (int loadfrom) |
| { |
| int filesize = 0; |
| switch (loadfrom) { |
| #ifdef MV_INCLUDE_USB |
| case 1: |
| { |
| filesize = load_from_usb(BootFile); |
| if (filesize <= 0) |
| { |
| printf("Failed to read file %s\n", BootFile); |
| return 0; |
| } |
| break; |
| } |
| #endif |
| default: |
| { |
| filesize = NetLoop(TFTPGET); |
| printf("Checking file size:"); |
| if (filesize == -1) |
| { |
| printf("\t[Fail]\n"); |
| return 0; |
| } |
| break; |
| } |
| } |
| return filesize; |
| } |
| |
| #if defined(MV_NAND_BOOT) || defined(MV_NAND) |
| /* Boot from NAND flash */ |
| /* Write u-boot image into the nand flash */ |
| int nand_burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int loadfrom, int argc, char * const argv[]) |
| { |
| int filesize = 0; |
| MV_U32 ret = 0; |
| extern char console_buffer[]; |
| nand_info_t *nand = &nand_info[0]; |
| size_t blocksize = nand_info[0].erasesize; |
| size_t env_offset = CONFIG_ENV_OFFSET_NAND; |
| size_t size = CONFIG_UBOOT_SIZE; |
| size_t offset = 0; |
| |
| /* Align U-Boot size to currently used blocksize */ |
| size = ((size + (blocksize - 1)) & (~(blocksize-1))); |
| |
| #if defined(CONFIG_SKIP_BAD_BLOCK) |
| int i = 0; |
| int sum = 0; |
| |
| while(i * blocksize < nand_info[0].size) { |
| if (!nand_block_isbad(&nand_info[0], (i * blocksize))) |
| sum += blocksize; |
| else { |
| sum = 0; |
| offset = (i + 1) * blocksize; |
| } |
| |
| if (sum >= size) |
| break; |
| i++; |
| } |
| #endif |
| |
| /* verify requested source is valid */ |
| if ((filesize = fetch_uboot_file (loadfrom)) <= 0) |
| return 0; |
| |
| if (filesize > CONFIG_UBOOT_SIZE) { |
| printf("Boot image is too big. Maximum size is %d bytes\n", CONFIG_UBOOT_SIZE); |
| return 0; |
| } |
| printf("\t[Done]\n"); |
| printf("Override Env parameters to default? [y/N]"); |
| readline(" "); |
| if( strcmp(console_buffer,"Y") == 0 || |
| strcmp(console_buffer,"yes") == 0 || |
| strcmp(console_buffer,"y") == 0 ) { |
| |
| printf("Erasing 0x%x - 0x%x:",env_offset, env_offset + CONFIG_ENV_RANGE_NAND); |
| nand_erase(nand, env_offset, CONFIG_ENV_RANGE_NAND); |
| printf("\t[Done]\n"); |
| } |
| |
| printf("Erasing 0x%x - 0x%x: ", offset, offset + size); |
| nand_erase(nand, offset, size); |
| printf("\t[Done]\n"); |
| |
| printf("Writing image to NAND:"); |
| ret = nand_write(nand, offset, &size, (u_char *)load_addr); |
| if (ret) |
| printf("\t[Fail]\n"); |
| else |
| printf("\t[Done]\n"); |
| |
| return 1; |
| } |
| |
| #endif /* defined(CONFIG_NAND_BOOT) */ |
| |
| #if defined(MV_SPI_BOOT) || defined(MV_INCLUDE_SPI) |
| |
| /* Boot from SPI flash */ |
| /* Write u-boot image into the SPI flash */ |
| int spi_burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int loadfrom, int argc, char * const argv[]) |
| { |
| int filesize = 0; |
| MV_U32 ret = 0; |
| extern char console_buffer[]; |
| load_addr = CONFIG_SYS_LOAD_ADDR; |
| |
| if(!flash) { |
| flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, |
| CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); |
| if (!flash) { |
| printf("Failed to probe SPI Flash\n"); |
| set_default_env("!spi_flash_probe() failed"); |
| return 0; |
| } |
| } |
| |
| /* verify requested source is valid */ |
| if ((filesize = fetch_uboot_file (loadfrom)) <= 0) |
| return 0; |
| |
| printf("\t\t[Done]\n"); |
| printf("Override Env parameters to default? [y/N]"); |
| readline(" "); |
| |
| #ifdef CONFIG_SPI_FLASH_PROTECTION |
| printf("Unprotecting flash:"); |
| spi_flash_protect(flash, 0); |
| printf("\t\t[Done]\n"); |
| #endif |
| if( strcmp(console_buffer,"Y") == 0 || |
| strcmp(console_buffer,"yes") == 0 || |
| strcmp(console_buffer,"y") == 0 ) { |
| |
| printf("Erasing 0x%x - 0x%x:",CONFIG_ENV_OFFSET_SPI, CONFIG_ENV_OFFSET_SPI + CONFIG_ENV_SIZE_SPI); |
| spi_flash_erase(flash, CONFIG_ENV_OFFSET_SPI, CONFIG_ENV_SIZE_SPI); |
| printf("\t[Done]\n"); |
| } |
| if (filesize > CONFIG_ENV_OFFSET_SPI) |
| { |
| printf("Error: Image size (%x) exceeds environment variables offset (%x). ",filesize,CONFIG_ENV_OFFSET); |
| return 0; |
| } |
| printf("Erasing 0x%x - 0x%x: ",0, 0 + CONFIG_ENV_OFFSET_SPI); |
| spi_flash_erase(flash, 0, CONFIG_ENV_OFFSET_SPI); |
| printf("\t\t[Done]\n"); |
| |
| printf("Writing image to flash:"); |
| ret = spi_flash_write(flash, 0, filesize, (const void *)load_addr); |
| |
| if (ret) |
| printf("\t\t[Err!]\n"); |
| else |
| printf("\t\t[Done]\n"); |
| |
| #ifdef CONFIG_SPI_FLASH_PROTECTION |
| printf("Protecting flash:"); |
| spi_flash_protect(flash, 1); |
| printf("\t\t[Done]\n"); |
| #endif |
| return 1; |
| } |
| |
| #endif |
| |
| |
| #if defined(MV_NOR_BOOT) || (MV_INCLUDE_NOR) |
| |
| /* Boot from Nor flash */ |
| int nor_burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int loadfrom, int argc, char * const argv[]) |
| { |
| int filesize = 0; |
| MV_U32 ret = 0; |
| extern char console_buffer[]; |
| load_addr = CONFIG_SYS_LOAD_ADDR; |
| // MV_U32 s_first,s_end,env_sec; |
| |
| ulong stop_addr; |
| ulong start_addr; |
| |
| // s_first = flash_in_which_sec(&flash_info[0], CONFIG_SYS_MONITOR_BASE); |
| // s_end = flash_in_which_sec(&flash_info[0], CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN -1); |
| // env_sec = flash_in_which_sec(&flash_info[0], CONFIG_ENV_ADDR); |
| |
| |
| /* verify requested source is valid */ |
| if ((filesize = fetch_uboot_file (loadfrom)) <= 0) |
| return 0; |
| |
| printf("\t[Done]\n"); |
| printf("Override Env parameters to default? [y/N]"); |
| readline(" "); |
| if( strcmp(console_buffer,"Y") == 0 || |
| strcmp(console_buffer,"yes") == 0 || |
| strcmp(console_buffer,"y") == 0 ) { |
| |
| start_addr = CONFIG_ENV_ADDR; |
| stop_addr = start_addr + CONFIG_ENV_SIZE - 1; |
| |
| printf("Erasing sector 0x%x:",CONFIG_ENV_OFFSET); |
| flash_sect_protect (0, start_addr, stop_addr); |
| |
| flash_sect_erase (start_addr, stop_addr); |
| |
| flash_sect_protect (1, start_addr, stop_addr); |
| printf("\t[Done]\n"); |
| } |
| |
| start_addr = NOR_CS_BASE; |
| stop_addr = start_addr + CONFIG_ENV_OFFSET - 1; |
| |
| flash_sect_protect (0, start_addr, stop_addr); |
| |
| printf("Erasing 0x%x - 0x%x: ", (unsigned int)start_addr, (unsigned int)(start_addr + CONFIG_ENV_OFFSET)); |
| flash_sect_erase (start_addr, stop_addr); |
| printf("\t[Done]\n"); |
| |
| printf("Writing image to NOR:"); |
| ret = flash_write((char *)CONFIG_SYS_LOAD_ADDR, start_addr, filesize); |
| |
| if (ret) |
| printf("\t[Err!]\n"); |
| else |
| printf("\t[Done]\n"); |
| |
| flash_sect_protect (1, start_addr, stop_addr); |
| return 1; |
| } |
| |
| #endif /* MV_NOR_BOOT */ |
| |
| #if defined(MV_MMC_BOOT) |
| |
| /* Boot from SD/MMC/eMMC */ |
| /* Write u-boot image into SD/MMC/eMMC device */ |
| int mmc_burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int loadfrom, int argc, char * const argv[]) |
| { |
| int filesize = 0; |
| extern char console_buffer[]; |
| load_addr = CONFIG_SYS_LOAD_ADDR; |
| lbaint_t start_lba; |
| lbaint_t blk_count; |
| ulong blk_written; |
| ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); |
| struct mmc *mmc; |
| |
| start_lba = CONFIG_ENV_ADDR / CONFIG_ENV_SECT_SIZE; |
| blk_count = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE; |
| |
| mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); |
| if (!mmc) { |
| printf("No SD/MMC/eMMC card found\n"); |
| return 1; |
| } |
| |
| if (mmc_init(mmc)) { |
| printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC", CONFIG_SYS_MMC_ENV_DEV); |
| return 1; |
| } |
| |
| #ifdef CONFIG_SYS_MMC_ENV_PART |
| if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) { |
| if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, CONFIG_SYS_MMC_ENV_PART)) { |
| printf("MMC partition switch failed\n"); |
| return 1; |
| } |
| } |
| #endif |
| |
| /* verify requested source is valid */ |
| if ((filesize = fetch_uboot_file (loadfrom)) <= 0) |
| return 0; |
| |
| printf("\t\t[Done]\n"); |
| printf("Override Env parameters to default? [y/N]"); |
| readline(" "); |
| |
| if( strcmp(console_buffer,"Y") == 0 || |
| strcmp(console_buffer,"yes") == 0 || |
| strcmp(console_buffer,"y") == 0 ) { |
| |
| printf("Erasing 0x"LBAF" blocks starting at sector 0x"LBAF" :", blk_count, start_lba); |
| memset(buf, 0, CONFIG_ENV_SIZE); |
| blk_written = mmc_bwrite(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count, buf); |
| if (blk_written != blk_count) { |
| printf("\t[FAIL] - erased %#lx blocks\n", blk_written); |
| return 0; |
| } else |
| printf("\t[Done]\n"); |
| } |
| if (filesize > CONFIG_ENV_OFFSET) { |
| printf("Error: Image size (%x) exceeds environment variables offset (%x). ", filesize, CONFIG_ENV_OFFSET); |
| return 0; |
| } |
| |
| /* SD reserves LBA-0 for MBR and boots from LBA-1, MMC/eMMC boots from LBA-0 */ |
| start_lba = IS_SD(mmc) ? 1 : 0; |
| blk_count = filesize / CONFIG_ENV_SECT_SIZE; |
| if (filesize % CONFIG_ENV_SECT_SIZE) |
| blk_count += 1; |
| |
| printf("Writing image to %s(%d) at LBA 0x"LBAF" (0x"LBAF" blocks):", |
| IS_SD(mmc) ? "SD" : "MMC", CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count); |
| blk_written = mmc_bwrite(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count, (char *)CONFIG_SYS_LOAD_ADDR); |
| if (blk_written != blk_count) { |
| printf("\t[FAIL] - written %#lx blocks\n", blk_written); |
| return 0; |
| } else |
| printf("\t[Done]\n"); |
| |
| #ifdef CONFIG_SYS_MMC_ENV_PART |
| if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) |
| mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, mmc->part_num); |
| #endif |
| |
| return 1; |
| } |
| |
| #endif |
| |
| int burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| char destination_burn[DESTINATION_STRING]; |
| int loadfrom = 0; /* 0 - from tftp, 1 - from USB */ |
| |
| memset(destination_burn, '\0', sizeof(destination_burn)); |
| |
| if(fetch_bubt_cmd_args(argc, argv, &loadfrom,destination_burn) != MV_OK) |
| return 0; |
| |
| #if defined(MV_CROSS_FLASH_BOOT) |
| if (0 == strcmp(destination_burn, "nand")) { |
| #if defined(MV_NAND) || defined(MV_NAND_BOOT) |
| return nand_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| printf("\t[FAIL] - u-boot does not support a write to %s interface.\n",destination_burn); |
| return 0; |
| } |
| |
| if (0 == strcmp(destination_burn, "spi")) { |
| #if defined(MV_INCLUDE_SPI) || defined (MV_SPI_BOOT) |
| return spi_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| printf("\t[FAIL] - u-boot does not support a write to %s interface.\n",destination_burn); |
| return 0; |
| } |
| |
| if (0 == strcmp(destination_burn, "nor")) { |
| #if defined(MV_INCLUDE_NOR) || defined (MV_NOR_BOOT) |
| return nor_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| printf("\t[FAIL] - u-boot does not support a write to %s interface.\n",destination_burn); |
| return 0; |
| } |
| #endif |
| |
| #if defined(MV_NAND_BOOT) |
| return nand_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| #if defined(MV_SPI_BOOT) |
| return spi_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| #if defined(MV_NOR_BOOT) |
| return nor_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| #if defined(MV_MMC_BOOT) |
| return mmc_burn_uboot_cmd(cmdtp, flag, loadfrom, argc, argv); |
| #endif |
| |
| return 1; |
| } |
| |
| #if defined(MV_MMC_BOOT) |
| U_BOOT_CMD( |
| bubt, 3, 1, burn_uboot_cmd, |
| "bubt - Burn an image on the Boot device.\n", |
| " file-name \n" |
| "[file-name] [source] \n" |
| "\tBurn a binary image on the Boot Device, default file-name is u-boot.bin .\n" |
| "\tsource can be tftp or usb, default is tftp.\n" |
| ); |
| #else |
| U_BOOT_CMD( |
| bubt, 4, 1, burn_uboot_cmd, |
| "bubt - Burn an image on the Boot flash device.\n", |
| "[file-name] [destination [source]] \n" |
| "\tBurn a binary image on the Boot Device, default file-name is u-boot.bin .\n" |
| "\tsource can be tftp or usb, default is tftp.\n" |
| "\texample: bubt u-boot.bin nand tftp\n" |
| ); |
| #endif |