Merge "ipq4019: fdt_fixup: Delete the 'sd-ldo-gpios' property from sdhci node"
diff --git a/arch/arm/cpu/armv7/qca/common/smem.c b/arch/arm/cpu/armv7/qca/common/smem.c
index 8c12fc7..32e0810 100644
--- a/arch/arm/cpu/armv7/qca/common/smem.c
+++ b/arch/arm/cpu/armv7/qca/common/smem.c
@@ -649,6 +649,49 @@
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 133d6a4..070b83a 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 @@
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/board/qca/arm/ipq806x/ipq806x.c b/board/qca/arm/ipq806x/ipq806x.c
index 6e583ad..7af5148 100644
--- a/board/qca/arm/ipq806x/ipq806x.c
+++ b/board/qca/arm/ipq806x/ipq806x.c
@@ -535,6 +535,13 @@
uint32_t soc_version, soc_version_major, soc_version_minor;
int nodeoff, ret;
+ nodeoff = fdt_path_offset(blob, "/");
+
+ if (nodeoff < 0) {
+ printf("ipq: fdt fixup cannot find root node\n");
+ return;
+ }
+
ret = ipq_smem_get_socinfo_cpu_type(&cpu_type);
if (ret) {
return;
diff --git a/common/Makefile b/common/Makefile
index 2a1d9f8..4f6107f 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -101,6 +101,7 @@
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 0000000..6f91148
--- /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 <common.h>
+#include <command.h>
+#include <asm/arch-qca-common/smem.h>
+#include <part.h>
+#include <linux/mtd/mtd.h>
+#include <nand.h>
+#include <mmc.h>
+#include <sdhci.h>
+
+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 b294004..0e6e819 100644
--- a/include/configs/ipq40xx.h
+++ b/include/configs/ipq40xx.h
@@ -122,6 +122,7 @@
#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 40e1d6b..57af6e9 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 877eb25..b466956 100644
--- a/include/configs/ipq807x.h
+++ b/include/configs/ipq807x.h
@@ -140,6 +140,7 @@
#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