From 4bfeb00cc1ca4bcd459cffff69218aab231c19f6 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 25 Aug 2022 16:48:46 +0900 Subject: [PATCH 1/9] mtd: spi-nor-core: Rename s28hs512t prefix Change prefix to support all other devices in SEMPER S28 family. Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index c73636d7d11..b200457ecde 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3392,15 +3392,15 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) return 0; } -static int s28hs512t_erase_non_uniform(struct spi_nor *nor, loff_t addr) +static int s28hx_t_erase_non_uniform(struct spi_nor *nor, loff_t addr) { /* Factory default configuration: 32 x 4 KiB sectors at bottom. */ return spansion_erase_non_uniform(nor, addr, SPINOR_OP_S28_SE_4K, 0, SZ_128K); } -static int s28hs512t_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) +static int s28hx_t_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) { struct spi_mem_op op; u8 buf; @@ -3427,19 +3427,19 @@ static int s28hs512t_setup(struct spi_nor *nor, const struct flash_info *info, return ret; if (!(buf & SPINOR_REG_CYPRESS_CFR3V_UNISECT)) - nor->erase = s28hs512t_erase_non_uniform; + nor->erase = s28hx_t_erase_non_uniform; return spi_nor_default_setup(nor, info, params); } -static void s28hs512t_default_init(struct spi_nor *nor) +static void s28hx_t_default_init(struct spi_nor *nor) { nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; - nor->setup = s28hs512t_setup; + nor->setup = s28hx_t_setup; } -static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) +static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { /* * On older versions of the flash the xSPI Profile 1.0 table has the @@ -3469,10 +3469,10 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor, params->rdsr_addr_nbytes = 4; } -static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) +static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) { struct spi_mem_op op; u8 buf; @@ -3509,10 +3509,10 @@ static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, return 0; } -static struct spi_nor_fixups s28hs512t_fixups = { - .default_init = s28hs512t_default_init, - .post_sfdp = s28hs512t_post_sfdp_fixup, - .post_bfpt = s28hs512t_post_bfpt_fixup, +static struct spi_nor_fixups s28hx_t_fixups = { + .default_init = s28hx_t_default_init, + .post_sfdp = s28hx_t_post_sfdp_fixup, + .post_bfpt = s28hx_t_post_bfpt_fixup, }; #endif /* CONFIG_SPI_FLASH_S28HS512T */ @@ -3847,7 +3847,7 @@ void spi_nor_set_fixups(struct spi_nor *nor) #ifdef CONFIG_SPI_FLASH_S28HS512T if (!strcmp(nor->info->name, "s28hs512t")) - nor->fixups = &s28hs512t_fixups; + nor->fixups = &s28hx_t_fixups; #endif #ifdef CONFIG_SPI_FLASH_MT35XU From f422c4bec7c654d185abb9bb29f79738e3115323 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 25 Aug 2022 16:48:47 +0900 Subject: [PATCH 2/9] mtd: spi-nor-core: Rename configuration macro for S28 support Change configuration macro name to support all other devices in SEMPER S28 family. Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- configs/j721s2_evm_a72_defconfig | 2 +- configs/j721s2_evm_r5_defconfig | 2 +- drivers/mtd/spi/Kconfig | 10 +++++----- drivers/mtd/spi/spi-nor-core.c | 6 +++--- drivers/mtd/spi/spi-nor-ids.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/configs/j721s2_evm_a72_defconfig b/configs/j721s2_evm_a72_defconfig index 9fe30066899..2b2f80c4aaa 100644 --- a/configs/j721s2_evm_a72_defconfig +++ b/configs/j721s2_evm_a72_defconfig @@ -149,7 +149,7 @@ CONFIG_SPI_FLASH_SFDP_SUPPORT=y CONFIG_SPI_FLASH_SOFT_RESET=y CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y CONFIG_SPI_FLASH_SPANSION=y -CONFIG_SPI_FLASH_S28HS512T=y +CONFIG_SPI_FLASH_S28HX_T=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_MT35XU=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set diff --git a/configs/j721s2_evm_r5_defconfig b/configs/j721s2_evm_r5_defconfig index f74333f27cb..2de5d87bdb2 100644 --- a/configs/j721s2_evm_r5_defconfig +++ b/configs/j721s2_evm_r5_defconfig @@ -128,7 +128,7 @@ CONFIG_SPI_FLASH_SFDP_SUPPORT=y CONFIG_SPI_FLASH_SOFT_RESET=y CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y CONFIG_SPI_FLASH_SPANSION=y -CONFIG_SPI_FLASH_S28HS512T=y +CONFIG_SPI_FLASH_S28HX_T=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_MT35XU=y CONFIG_PINCTRL=y diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 096338f27bf..7b858a3a919 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -166,13 +166,13 @@ config SPI_FLASH_SPANSION help Add support for various Spansion SPI flash chips (S25FLxxx) -config SPI_FLASH_S28HS512T - bool "Cypress S28HS512T chip support" +config SPI_FLASH_S28HX_T + bool "Cypress SEMPER Octal (S28) chip support" depends on SPI_FLASH_SPANSION help - Add support for the Cypress S28HS512T chip. This is a separate config - because the fixup hooks for this flash add extra size overhead. Boards - that don't use the flash can disable this to save space. + Add support for the Cypress S28HL-T and S28HS-T chip. This is a separate + config because the fixup hooks for this flash add extra size overhead. + Boards that don't use the flash can disable this to save space. config SPI_FLASH_STMICRO bool "STMicro SPI flash support" diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index b200457ecde..a7879945986 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3333,7 +3333,7 @@ static struct spi_nor_fixups s25fl256l_fixups = { }; #endif -#ifdef CONFIG_SPI_FLASH_S28HS512T +#ifdef CONFIG_SPI_FLASH_S28HX_T /** * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes. * @nor: pointer to a 'struct spi_nor' @@ -3514,7 +3514,7 @@ static struct spi_nor_fixups s28hx_t_fixups = { .post_sfdp = s28hx_t_post_sfdp_fixup, .post_bfpt = s28hx_t_post_bfpt_fixup, }; -#endif /* CONFIG_SPI_FLASH_S28HS512T */ +#endif /* CONFIG_SPI_FLASH_S28HX_T */ #ifdef CONFIG_SPI_FLASH_MT35XU static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor) @@ -3845,7 +3845,7 @@ void spi_nor_set_fixups(struct spi_nor *nor) nor->fixups = &s25fl256l_fixups; #endif -#ifdef CONFIG_SPI_FLASH_S28HS512T +#ifdef CONFIG_SPI_FLASH_S28HX_T if (!strcmp(nor->info->name, "s28hs512t")) nor->fixups = &s28hx_t_fixups; #endif diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 65eb35a9185..e146d2464de 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -294,7 +294,7 @@ const struct flash_info spi_nor_ids[] = { USE_CLSR) }, { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, -#ifdef CONFIG_SPI_FLASH_S28HS512T +#ifdef CONFIG_SPI_FLASH_S28HX_T { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, #endif #endif From de9e8378a8f66c5547dc2e5942c7f89c5771d53a Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 25 Aug 2022 16:48:48 +0900 Subject: [PATCH 3/9] mtd: spi-nor-ids: Add s28hl512t, s28hl01gt, and s28hs01gt IDs Add flash info table entries for s28hl512gt, s28hl01gt, and s28hs01gt. These devices have the same functionality as s28hs512t. In spi-nor-core, use device ID byte to detect S28 family instead of device name. Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 12 +++++++----- drivers/mtd/spi/spi-nor-ids.c | 3 +++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index a7879945986..ec9b07a78f3 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3835,6 +3835,13 @@ void spi_nor_set_fixups(struct spi_nor *nor) nor->fixups = &s25hx_t_fixups; break; +#ifdef CONFIG_SPI_FLASH_S28HX_T + case 0x5a: /* S28HL (Octal, 3.3V) */ + case 0x5b: /* S28HS (Octal, 1.8V) */ + nor->fixups = &s28hx_t_fixups; + break; +#endif + default: break; } @@ -3845,11 +3852,6 @@ void spi_nor_set_fixups(struct spi_nor *nor) nor->fixups = &s25fl256l_fixups; #endif -#ifdef CONFIG_SPI_FLASH_S28HX_T - if (!strcmp(nor->info->name, "s28hs512t")) - nor->fixups = &s28hx_t_fixups; -#endif - #ifdef CONFIG_SPI_FLASH_MT35XU if (!strcmp(nor->info->name, "mt35xu512aba")) nor->fixups = &mt35xu512aba_fixups; diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index e146d2464de..5f8f3ec955d 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -295,7 +295,10 @@ const struct flash_info spi_nor_ids[] = { { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, #ifdef CONFIG_SPI_FLASH_S28HX_T + { INFO("s28hl512t", 0x345a1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hl01gt", 0x345a1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs01gt", 0x345b1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, #endif #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ From ee1c709cfde71b339a5c5dd0788522340c4c7e92 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 1 Sep 2022 15:05:30 +0900 Subject: [PATCH 4/9] mtd: spi-nor-core: Default to addr_width of 3 for configurable widths JESD216D-01 mentions that "defaults to 3-Byte mode; enters 4-Byte mode on command." Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index ec9b07a78f3..f8d56699690 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2236,6 +2236,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, /* Number of address bytes. */ switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: + case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: nor->addr_width = 3; break; From 4d60001fdf0c13ab1ccf720bb3cd6e5d385386bb Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 1 Sep 2022 15:05:31 +0900 Subject: [PATCH 5/9] mtd: spi-nor-core: Track flash's internal address mode The nor->addr_width tracks number of address bytes used in read/program/erase ops and eventually set to 4 for >16MB chips, regardless of flash's internal address mode. For Infineon SEMPER flash's, we use Read/Write Any Register commands for configuration and status check. These commands take 3- or 4-byte address depending on flash's internal address mode. Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 2 ++ include/linux/mtd/spi-nor.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index f8d56699690..08905a4055f 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2238,10 +2238,12 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4: nor->addr_width = 3; + nor->addr_mode_nbytes = 3; break; case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: nor->addr_width = 4; + nor->addr_mode_nbytes = 4; break; default: diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 638d807ee55..30f15452aa6 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -494,6 +494,10 @@ struct spi_flash { * @rdsr_dummy dummy cycles needed for Read Status Register command. * @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register * command. + * @addr_mode_nbytes: number of address bytes of current address mode. Useful + * when the flash operates with 4B opcodes but needs the + * internal address mode for opcodes that don't have a 4B + * opcode correspondent. * @bank_read_cmd: Bank read cmd * @bank_write_cmd: Bank write cmd * @bank_curr: Current flash bank @@ -540,6 +544,7 @@ struct spi_nor { u8 program_opcode; u8 rdsr_dummy; u8 rdsr_addr_nbytes; + u8 addr_mode_nbytes; #ifdef CONFIG_SPI_FLASH_BAR u8 bank_read_cmd; u8 bank_write_cmd; From f58e7b24faae2f01f59182405fb0a11ff2707cb7 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 1 Sep 2022 15:05:32 +0900 Subject: [PATCH 6/9] mtd: spi-nor-core: Rework spansion_read/write_any_reg() to use addr_mode_nbytes Read/Write Any Register commands take 3- or 4- byte address depending on flash's internal address mode. The nor->addr_width tracks number of address bytes used in read/program/erase ops that can be 4 (with 4B opcodes) regardless of flash's internal address mode. The nor->addr_mode_nbytes tracks flash's internal address mode so replace nor->addr_width by that. Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 08905a4055f..4109e0463a0 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -329,10 +329,10 @@ static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, u8 *val) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDAR, 1), - SPI_MEM_OP_ADDR(nor->addr_width, addr, 1), - SPI_MEM_OP_DUMMY(dummy / 8, 1), - SPI_MEM_OP_DATA_IN(1, NULL, 1)); + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDAR, 1), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), + SPI_MEM_OP_DUMMY(dummy / 8, 1), + SPI_MEM_OP_DATA_IN(1, NULL, 1)); return spi_nor_read_write_reg(nor, &op, val); } @@ -340,10 +340,10 @@ static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1), - SPI_MEM_OP_ADDR(nor->addr_width, addr, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, NULL, 1)); + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, NULL, 1)); return spi_nor_read_write_reg(nor, &op, &val); } From 7a4b6f8cf72e3566fd67ea840d248d8a34b8083e Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Thu, 1 Sep 2022 15:05:33 +0900 Subject: [PATCH 7/9] mtd: spi-nor-core: Rework s25hx_t_post_bfpt_fixup() for flash's internal address mode The flash's internal address mode is tracked by nor->add_mode_nbytes and it is set to 3 in BFPT parse. SEMPER multi-die package parts (>1Gb) are 3- or 4-byte address mode by default, depending on model number. We need to make sure that 4-byte address mode is used for multi-die package parts. For single-die package parts (<=1Gb), registers can be accessed by 3-byte address. Read, program, and erase use the 4B opcodes that always take 4-byte address regardless of flash's internal address mode. Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 4109e0463a0..44674cbec06 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -161,6 +161,7 @@ struct sfdp_header { #define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ #define BFPT_DWORD16_SOFT_RST BIT(12) +#define BFPT_DWORD16_EX4B_PWRCYC BIT(21) #define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) #define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */ @@ -3276,10 +3277,24 @@ static int s25hx_t_post_bfpt_fixup(struct spi_nor *nor, nor->erase_opcode = SPINOR_OP_SE_4B; nor->mtd.erasesize = nor->info->sector_size; - ret = set_4byte(nor, nor->info, 1); - if (ret) - return ret; - nor->addr_width = 4; + /* + * The default address mode in multi-die package parts (>1Gb) may be + * 3- or 4-byte, depending on model number. BootROM code in some SoCs + * use 3-byte mode for backward compatibility and should switch to + * 4-byte mode after BootROM phase. Since registers in the 2nd die are + * mapped within 32-bit address space, we need to make sure the flash is + * in 4-byte address mode. The default address mode can be distinguished + * by BFPT 16th DWORD. Power cycle exits 4-byte address mode if default + * is 3-byte address mode. + */ + if (params->size > SZ_128M) { + if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) { + ret = set_4byte(nor, nor->info, 1); + if (ret) + return ret; + } + nor->addr_mode_nbytes = 4; + } /* * The page_size is set to 512B from BFPT, but it actually depends on From e28d3ead7258ce1deb87003d0064b16ec50abc81 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Mon, 12 Sep 2022 14:25:40 +0900 Subject: [PATCH 8/9] mtd: spi-nor-core: Fix index value for SCCR dwords Array index for SCCR 22th DWORD should be 21. Fixes: bebdc237507c ("mtd: spi-nor: Parse SFDP SCCR Map") Signed-off-by: Takahiro Kuwano Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 44674cbec06..78de3c52816 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2520,7 +2520,7 @@ static int spi_nor_parse_sccr(struct spi_nor *nor, for (i = 0; i < sccr_header->length; i++) table[i] = le32_to_cpu(table[i]); - if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[22])) + if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[21])) nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; out: From 622b5d356136f9172db7fe7ba240cd9e45097a19 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 28 Sep 2022 18:45:04 +0200 Subject: [PATCH 9/9] cmd: sf: Handle unaligned 'update' start offset Currently the 'sf update' command fails in case the 'start' offset is not aligned to SPI NOR erase block size. Add the missing alignment calculation. In case the start offset is in the middle of erase block, round start address down to the nearest aligned one, compare only the updated data between what is in the SPI NOR and what is being written, copy new data at offset of the compare buffer, and write back the entire erase block. This is useful e.g. on i.MX6Q where the u-boot-with-spl.imx is at offset 0x400 in the SPI NOR, while the SPI NOR may have erase block size e.g. 0x1000 bytes. Signed-off-by: Marek Vasut Reviewed-by: Jagan Teki --- cmd/sf.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cmd/sf.c b/cmd/sf.c index bd102f5af9d..f9b2d9a47a7 100644 --- a/cmd/sf.c +++ b/cmd/sf.c @@ -179,16 +179,18 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset, size_t len, const char *buf, char *cmp_buf, size_t *skipped) { char *ptr = (char *)buf; + u32 start_offset = offset % flash->sector_size; + u32 read_offset = offset - start_offset; - debug("offset=%#x, sector_size=%#x, len=%#zx\n", - offset, flash->sector_size, len); + debug("offset=%#x+%#x, sector_size=%#x, len=%#zx\n", + read_offset, start_offset, flash->sector_size, len); /* Read the entire sector so to allow for rewriting */ - if (spi_flash_read(flash, offset, flash->sector_size, cmp_buf)) + if (spi_flash_read(flash, read_offset, flash->sector_size, cmp_buf)) return "read"; /* Compare only what is meaningful (len) */ - if (memcmp(cmp_buf, buf, len) == 0) { - debug("Skip region %x size %zx: no change\n", - offset, len); + if (memcmp(cmp_buf + start_offset, buf, len) == 0) { + debug("Skip region %x+%x size %zx: no change\n", + start_offset, read_offset, len); *skipped += len; return NULL; } @@ -197,7 +199,7 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset, return "erase"; /* If it's a partial sector, copy the data into the temp-buffer */ if (len != flash->sector_size) { - memcpy(cmp_buf, buf, len); + memcpy(cmp_buf + start_offset, buf, len); ptr = cmp_buf; } /* Write one complete sector */ @@ -238,6 +240,8 @@ static int spi_flash_update(struct spi_flash *flash, u32 offset, for (; buf < end && !err_oper; buf += todo, offset += todo) { todo = min_t(size_t, end - buf, flash->sector_size); + todo = min_t(size_t, end - buf, + flash->sector_size - (offset % flash->sector_size)); if (get_timer(last_update) > 100) { printf(" \rUpdating, %zu%% %lu B/s", 100 - (end - buf) / scale,