diff --git a/arch/arm/cpu/armv7/qca/common/smem.c b/arch/arm/cpu/armv7/qca/common/smem.c index 8c12fc7f49..32e081095a 100644 --- a/arch/arm/cpu/armv7/qca/common/smem.c +++ b/arch/arm/cpu/armv7/qca/common/smem.c @@ -649,6 +649,49 @@ unsigned int get_which_flash_param(char *part_name) return flash_var; } +/* + * getpart_offset_size - retreive partition offset and size + * @part_name - partition name + * @offset - location where the offset of partition to be stored + * @size - location where partition size to be stored + * + * Retreive partition offset and size in bytes with respect to the + * partition specific flash block size + */ +int getpart_offset_size(char *part_name, uint32_t *offset, uint32_t *size) +{ + int i; + uint32_t bsize; + qca_smem_flash_info_t *sfi = &qca_smem_flash_info; + + for (i = 0; i < smem_ptable.len; i++) { + struct smem_ptn *p = &smem_ptable.parts[i]; + loff_t psize; + if (!strncmp(p->name, part_name, SMEM_PTN_NAME_MAX)) { + bsize = get_part_block_size(p, sfi); + if (p->size == (~0u)) { + /* + * Partition size is 'till end of device', calculate + * appropriately + */ + psize = nand_info[get_device_id_by_part(p)].size + - (((loff_t)p->start) * bsize); + } else { + psize = ((loff_t)p->size) * bsize; + } + + *offset = ((loff_t)p->start) * bsize; + *size = psize; + break; + } + } + + if (i == smem_ptable.len) + return -ENOENT; + + return 0; +} + int do_smeminfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { qca_smem_flash_info_t *sfi = &qca_smem_flash_info; diff --git a/arch/arm/include/asm/arch-qca-common/smem.h b/arch/arm/include/asm/arch-qca-common/smem.h index 133d6a4773..070b83a1b4 100644 --- a/arch/arm/include/asm/arch-qca-common/smem.h +++ b/arch/arm/include/asm/arch-qca-common/smem.h @@ -60,6 +60,7 @@ int smem_get_boot_flash(uint32_t *flash_type, uint32_t *flash_block_size, uint32_t *flash_density); int smem_getpart(char *name, uint32_t *start, uint32_t *size); +int getpart_offset_size(char *part_name, uint32_t *offset, uint32_t *size); unsigned int smem_get_board_machtype(void); uint32_t get_nand_block_size(uint8_t dev_id); unsigned int get_which_flash_param(char *part_name); diff --git a/common/Makefile b/common/Makefile index 2a1d9f8331..4f6107fe41 100644 --- a/common/Makefile +++ b/common/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_CMD_FDC) += cmd_fdc.o obj-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o obj-$(CONFIG_CMD_FITUPD) += cmd_fitupd.o obj-$(CONFIG_CMD_FLASH) += cmd_flash.o +obj-$(CONFIG_CMD_FLASHWRITE) += cmd_flashwrite.o ifdef CONFIG_FPGA obj-$(CONFIG_CMD_FPGA) += cmd_fpga.o endif diff --git a/common/cmd_flashwrite.c b/common/cmd_flashwrite.c new file mode 100644 index 0000000000..6f91148413 --- /dev/null +++ b/common/cmd_flashwrite.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * FlashWrite command support + */ +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; +#ifndef CONFIG_SDHCI_SUPPORT +extern qca_mmc mmc_host; +#else +extern struct sdhci_host mmc_host; +#endif + +#define SMEM_PTN_NAME_MAX 16 + +static int write_to_flash(int flash_type, uint32_t address, uint32_t offset, +uint32_t part_size, uint32_t file_size, char *layout) +{ + + char runcmd[256]; + int nand_dev = CONFIG_NAND_FLASH_INFO_IDX; + + if (flash_type == SMEM_BOOT_NAND_FLASH) { + + snprintf(runcmd, sizeof(runcmd), "nand device %d && ", nand_dev); + + if (strcmp(layout, "default") != 0) { + + snprintf(runcmd + strlen(runcmd), sizeof(runcmd), + "ipq_nand %s && ", layout); + } + + snprintf(runcmd + strlen(runcmd), sizeof(runcmd), + "nand erase 0x%x 0x%x && " + "nand write 0x%x 0x%x 0x%x && ", + offset, part_size, + address, offset, file_size); + + } else if (flash_type == SMEM_BOOT_MMC_FLASH) { + + snprintf(runcmd, sizeof(runcmd), + "mmc erase 0x%x 0x%x && " + "mmc write 0x%x 0x%x 0x%x && ", + offset, part_size, + address, offset, file_size); + + } else if (flash_type == SMEM_BOOT_SPI_FLASH) { + + snprintf(runcmd, sizeof(runcmd), + "sf probe && " + "sf erase 0x%x 0x%x && " + "sf write 0x%x 0x%x 0x%x && ", + offset, part_size, + address, offset, file_size); + } + + if (run_command(runcmd, 0) != CMD_RET_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static int do_flash(cmd_tbl_t *cmdtp, int flag, int argc, +char * const argv[]) +{ + uint32_t load_addr, offset, part_size, file_size, adj_size; + uint32_t size_block, start_block, file_size_cpy; + char *part_name = NULL, *filesize; + int flash_type, ret, retn; + unsigned int active_part = 0; + char *layout = NULL; +#ifdef CONFIG_IPQ806X + char* layout_linux[] = {"rootfs", "0:BOOTCONFIG", "0:BOOTCONFIG1"}; + int len, i; +#endif + retn = CMD_RET_FAILURE; + + block_dev_desc_t *blk_dev; + disk_partition_t disk_info; + qca_smem_flash_info_t *sfi = &qca_smem_flash_info; + nand_info_t *nand = &nand_info[CONFIG_NAND_FLASH_INFO_IDX]; + + if ((argc < 3) || (argc > 4)) + return CMD_RET_USAGE; + + if (argc == 4) + file_size = simple_strtoul(argv[3], NULL, 16); + else { + filesize = getenv("filesize"); + if (filesize != NULL) + file_size = simple_strtoul(filesize, NULL, 16); + else + return CMD_RET_USAGE; + } + + if (strncmp(argv[2], "default", 7) == 0) + load_addr = CONFIG_SYS_LOAD_ADDR; + else + load_addr = simple_strtoul(argv[2], NULL, 16); + + flash_type = sfi->flash_type; + part_name = argv[1]; + + if (sfi->flash_type == SMEM_BOOT_NAND_FLASH) { + + ret = smem_getpart(part_name, &start_block, &size_block); + if (ret) + return retn; + + offset = sfi->flash_block_size * start_block; + part_size = sfi->flash_block_size * size_block; + layout = "default"; +#ifdef CONFIG_IPQ806X + len = sizeof(layout_linux)/sizeof(layout_linux[0]); + + for (i = 0; i < len; i++) { + + if (!strncmp(layout_linux[i], part_name, + SMEM_PTN_NAME_MAX)) { + layout = "linux"; + break; + } + } + + if (i == len ) + layout = "sbl"; +#endif + + } else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH) { + + blk_dev = mmc_get_dev(mmc_host.dev_num); + if (blk_dev != NULL) { + + ret = get_partition_info_efi_by_name(blk_dev, + part_name, &disk_info); + if (ret) + return retn; + + offset = (ulong)disk_info.start; + part_size = (ulong)disk_info.size; + file_size_cpy = file_size; + } + + } else if (sfi->flash_type == SMEM_BOOT_SPI_FLASH) { + + if (get_which_flash_param(part_name)) { + + /* NOR + NAND*/ + flash_type = SMEM_BOOT_NAND_FLASH; + ret = getpart_offset_size(part_name, &offset, &part_size); + if (ret) + return retn; + + } else if ((sfi->flash_secondary_type == SMEM_BOOT_NAND_FLASH) + && (strncmp(part_name, "rootfs", 6) == 0)) { + + /* IPQ806X - NOR + NAND */ + flash_type = SMEM_BOOT_NAND_FLASH; + + if (sfi->rootfs.offset == 0xBAD0FF5E) { + if (smem_bootconfig_info() == 0) + active_part = get_rootfs_active_partition(); + + offset = (ulong) active_part * IPQ_NAND_ROOTFS_SIZE; + part_size = (ulong) IPQ_NAND_ROOTFS_SIZE; + } + + }else if ((smem_getpart(part_name, &start_block, &size_block) + == -ENOENT) && (sfi->rootfs.offset == 0xBAD0FF5E)){ + + /* NOR + EMMC */ + flash_type = SMEM_BOOT_MMC_FLASH; + + blk_dev = mmc_get_dev(mmc_host.dev_num); + if (blk_dev != NULL) { + + ret = get_partition_info_efi_by_name(blk_dev, + part_name, &disk_info); + if (ret) + return retn; + + offset = (ulong)disk_info.start; + part_size = (ulong)disk_info.size; + file_size_cpy = file_size; + } + + } else { + + ret = smem_getpart(part_name, &start_block, + &size_block); + if (ret) + return retn; + + offset = sfi->flash_block_size * start_block; + part_size = sfi->flash_block_size * size_block; + } + } + + if (flash_type == SMEM_BOOT_NAND_FLASH) { + + adj_size = file_size % nand->writesize; + if (adj_size) + file_size = file_size + (nand->writesize - adj_size); + } + + if (flash_type == SMEM_BOOT_MMC_FLASH) { + + file_size = file_size / disk_info.blksz; + adj_size = file_size_cpy % disk_info.blksz; + if (adj_size) + file_size = file_size + 1; + } + + ret = write_to_flash(flash_type, load_addr, offset, part_size, + file_size, layout); + +return ret; +} + +U_BOOT_CMD( + flash, 4, 0, do_flash, + "flash part_name load_addr [file_size] \n" + "\tflash part_name 'default' \n", + "flash the image at load_addr, given file_size in hex\n" +); + diff --git a/include/configs/ipq40xx.h b/include/configs/ipq40xx.h index b294004f53..0e6e8199cc 100644 --- a/include/configs/ipq40xx.h +++ b/include/configs/ipq40xx.h @@ -122,6 +122,7 @@ typedef struct { #define QCA_BOOT_PARAMS_ADDR (QCA_KERNEL_START_ADDR + 0x100) #endif #define CONFIG_FLASH_PROTECT +#define CONFIG_CMD_FLASHWRITE /* Environment */ #define CONFIG_ARCH_CPU_INIT diff --git a/include/configs/ipq806x.h b/include/configs/ipq806x.h index 40e1d6b2a9..57af6e958f 100644 --- a/include/configs/ipq806x.h +++ b/include/configs/ipq806x.h @@ -93,6 +93,7 @@ #define CONFIG_SYS_DEVICE_NULLDEV #define CONFIG_FLASH_PROTECT +#define CONFIG_CMD_FLASHWRITE /* Environment */ #define CONFIG_MSM_PCOMM diff --git a/include/configs/ipq807x.h b/include/configs/ipq807x.h index 877eb25cda..b466956b3d 100644 --- a/include/configs/ipq807x.h +++ b/include/configs/ipq807x.h @@ -140,6 +140,7 @@ extern loff_t board_env_size; #define CONFIG_ENV_IS_IN_NAND 1 #define CONFIG_FLASH_PROTECT +#define CONFIG_CMD_FLASHWRITE /* Allow to overwrite serial and ethaddr */ #define CONFIG_ENV_OVERWRITE