[PATCH v2 0/9] mtd: spi-nor: Add support for Infineon S28HS02GT

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Infineon S28HS02GT is 1.8V, 2Gb (256MB) NOR Flash memory with Octal interface. It is a dual-die package parts and has same features with existing S28 series.
The goal of this series of patches is to add S28HS02GT support. Before adding device ID to the table, some reworks are done to simplify the support structure for all other S25Hx-T and S28Hx-T families.
Tested newly added S28HS02GT and other S25Hx-T and S28Hx-T devices on Zynq-7000 platform with Infineon SPI controller.
Only summary datasheet is available on web. https://www.infineon.com/dgdl/Infineon-S28HS02GT_S28HS04GT_S28HL02GT_S28HL04...
Please send an email to me for full version of the datasheet.
Changes in v2: - Rebased
Takahiro Kuwano (9): mtd: spi-nor-core: Clean up macros for Infineon(Cypress) S25 and S28 mtd: spi-nor-core: Consolidate non-uniform erase helpers for S25 and S28 mtd: spi-nor-core: Rework spansion_read_any_reg() to support Octal DTR mode mtd: spi-nor-core: Use CLPEF(0x82) as alternative to CLSR(0x30) for S25 and S28 mtd: spi-nor-core: Rework s25_mdp_ready() to support Octal DTR mode mtd: spi-nor-core: Consolidate setup() hook for Infineon(Cypress) S25 and S28 mtd: spi-nor-core: Consolidate post_bfpt_fixup() for Infineon(Cypress) S25 and S28 mtd: spi-nor-core: Rework spi_nor_cypress_octal_dtr_enable() mtd: spi-nor-ids: Add Infineon(Cypress) s28hs02gt ID
drivers/mtd/spi/spi-nor-core.c | 224 +++++++++++++-------------------- drivers/mtd/spi/spi-nor-ids.c | 1 + include/linux/mtd/spi-nor.h | 14 +-- 3 files changed, 91 insertions(+), 148 deletions(-)

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Some macro definitions used in Infineon(Cypress) S25 and S28 series are redundant and some have inconsistent prefix. This patch removes redundant ones and renames some to have same prefix as others.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 26 ++++++++++++++------------ include/linux/mtd/spi-nor.h | 11 +++-------- 2 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 9a1801ba93..a2ef65cf6f 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -331,7 +331,7 @@ 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(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 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)); @@ -342,7 +342,7 @@ 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(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(1, NULL, 1)); @@ -714,7 +714,7 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, */ static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) { - u32 reg_addr = addr_base + SPINOR_REG_ADDR_STR1V; + u32 reg_addr = addr_base + SPINOR_REG_CYPRESS_STR1V; u8 sr; int ret;
@@ -1856,7 +1856,7 @@ static int macronix_quad_enable(struct spi_nor *nor) static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, u8 dummy) { - u32 addr = addr_base + SPINOR_REG_ADDR_CFR1V; + u32 addr = addr_base + SPINOR_REG_CYPRESS_CFR1V;
u8 cr; int ret; @@ -3263,11 +3263,11 @@ static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, * Read CR3V to check if uniform sector is selected. If not, assign an * erase hook that supports non-uniform erase. */ - ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_CFR3V, + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, S25FS_S_RDAR_DUMMY, &cfr3v); if (ret) return ret; - if (!(cfr3v & CFR3V_UNHYSA)) + if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_UNISECT)) nor->erase = s25fs_s_erase_non_uniform;
return spi_nor_default_setup(nor, info, params); @@ -3366,7 +3366,8 @@ static int s25_setup(struct spi_nor *nor, const struct flash_info *info, * uniform 128KB only due to complexity of non-uniform layout. */ if (nor->info->id[4] == S25FS256T_ID4) { - ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_ARCFN, 8, &cr); + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_ARCFN, 8, + &cr); if (ret) return ret;
@@ -3380,10 +3381,10 @@ static int s25_setup(struct spi_nor *nor, const struct flash_info *info, * Read CFR3V to check if uniform sector is selected. If not, assign an * erase hook that supports non-uniform erase. */ - ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_CFR3V, 0, &cr); + ret = spansion_read_any_reg(nor, SPINOR_REG_CYPRESS_CFR3V, 0, &cr); if (ret) return ret; - if (!(cr & CFR3V_UNHYSA)) + if (!(cr & SPINOR_REG_CYPRESS_CFR3_UNISECT)) nor->erase = s25_erase_non_uniform;
/* @@ -3444,12 +3445,13 @@ static int s25_post_bfpt_fixup(struct spi_nor *nor, * dies are configured to 512B buffer. */ for (addr = 0; addr < params->size; addr += SZ_128M) { - ret = spansion_read_any_reg(nor, addr + SPINOR_REG_ADDR_CFR3V, - 0, &cfr3v); + ret = spansion_read_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR3V, 0, + &cfr3v); if (ret) return ret;
- if (!(cfr3v & CFR3V_PGMBUF)) { + if (!(cfr3v & SPINOR_REG_CYPRESS_CFR3_PGSZ)) { params->page_size = 256; return 0; } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 2861b73edb..f9a55c8e74 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -136,14 +136,6 @@ #define SPINOR_OP_BRRD 0x16 /* Bank register read */ #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ #define SPINOR_OP_EX4B_CYPRESS 0xB8 /* Exit 4-byte mode */ -#define SPINOR_OP_RDAR 0x65 /* Read any register */ -#define SPINOR_OP_WRAR 0x71 /* Write any register */ -#define SPINOR_REG_ADDR_STR1V 0x00800000 -#define SPINOR_REG_ADDR_CFR1V 0x00800002 -#define SPINOR_REG_ADDR_CFR3V 0x00800004 -#define SPINOR_REG_ADDR_ARCFN 0x00000006 -#define CFR3V_UNHYSA BIT(3) /* Uniform sectors or not */ -#define CFR3V_PGMBUF BIT(4) /* Program buffer size */
/* Used for Micron flashes only. */ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ @@ -189,6 +181,9 @@ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ #define SPINOR_OP_S28_SE_4K 0x21 +#define SPINOR_REG_CYPRESS_ARCFN 0x00000006 +#define SPINOR_REG_CYPRESS_STR1V 0x00800000 +#define SPINOR_REG_CYPRESS_CFR1V 0x00800002 #define SPINOR_REG_CYPRESS_CFR2V 0x00800003 #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR3V 0x00800004

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Some macro definitions used in Infineon(Cypress) S25 and S28 series are redundant and some have inconsistent prefix. This patch removes redundant ones and renames some to have same prefix as others.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s25_erase_non_uniform() and s28hx_t_erase_uniform() support hybrid sector layout (32 x 4KB sectors overlaid at bottom address) and doing same thing. Consolidate them into single helper named s25_s28_erase_non_uniform().
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 13 +++---------- include/linux/mtd/spi-nor.h | 1 - 2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index a2ef65cf6f..f62a2f2008 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3344,7 +3344,7 @@ static int s25_quad_enable(struct spi_nor *nor) return 0; }
-static int s25_erase_non_uniform(struct spi_nor *nor, loff_t addr) +static int s25_s28_erase_non_uniform(struct spi_nor *nor, loff_t addr) { /* Support 32 x 4KB sectors at bottom */ return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, @@ -3385,7 +3385,7 @@ static int s25_setup(struct spi_nor *nor, const struct flash_info *info, if (ret) return ret; if (!(cr & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s25_erase_non_uniform; + nor->erase = s25_s28_erase_non_uniform;
/* * For the multi-die package parts, the ready() hook is needed to check @@ -3558,13 +3558,6 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) return 0; }
-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 s28hx_t_setup(struct spi_nor *nor, const struct flash_info *info, const struct spi_nor_flash_parameter *params) { @@ -3593,7 +3586,7 @@ static int s28hx_t_setup(struct spi_nor *nor, const struct flash_info *info, return ret;
if (!(buf & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s28hx_t_erase_non_uniform; + nor->erase = s25_s28_erase_non_uniform;
return spi_nor_default_setup(nor, info, params); } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index f9a55c8e74..ebe38306a1 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -180,7 +180,6 @@ /* For Cypress flash. */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ -#define SPINOR_OP_S28_SE_4K 0x21 #define SPINOR_REG_CYPRESS_ARCFN 0x00000006 #define SPINOR_REG_CYPRESS_STR1V 0x00800000 #define SPINOR_REG_CYPRESS_CFR1V 0x00800002

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s25_erase_non_uniform() and s28hx_t_erase_uniform() support hybrid sector layout (32 x 4KB sectors overlaid at bottom address) and doing same thing. Consolidate them into single helper named s25_s28_erase_non_uniform().
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
In Infineon multi-die package parts, we need to use Read Any Register op to read status register in 2nd or further die. Infineon S28HS02GT is dual-die package and supports Octal DTR interface. To support this, spansion_read_any_reg() needs to be reworked. Implementation is similar to existing read_sr() that already supports Octal DTR mode.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index f62a2f2008..3f761b9b9e 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -331,12 +331,36 @@ 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_RD_ANY_REG, 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)); + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), + SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 0), + SPI_MEM_OP_DUMMY(dummy, 0), + SPI_MEM_OP_DATA_IN(1, NULL, 0)); + u8 buf[2]; + int ret; + + spi_nor_setup_op(nor, &op, nor->reg_proto); + + /* + * In Octal DTR mode, the number of address bytes is always 4 regardless + * of addressing mode setting. + */ + if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) + op.addr.nbytes = 4; + + /* + * We don't want to read only one byte in DTR mode. So, read 2 and then + * discard the second byte. + */ + if (spi_nor_protocol_is_dtr(nor->reg_proto)) + op.data.nbytes = 2;
- return spi_nor_read_write_reg(nor, &op, val); + ret = spi_nor_read_write_reg(nor, &op, buf); + if (ret) + return ret; + + *val = buf[0]; + + return 0; }
static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val)

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
In Infineon multi-die package parts, we need to use Read Any Register op to read status register in 2nd or further die. Infineon S28HS02GT is dual-die package and supports Octal DTR interface. To support this, spansion_read_any_reg() needs to be reworked. Implementation is similar to existing read_sr() that already supports Octal DTR mode.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Infineon(Cypress) S28Hx-T family does not support legacy CLSR(0x30) opcode. Instead, it supports CLPEF(0x82) which has the same functionality as CLSR. spansion_sr_ready() is for multi-die package parts including S28HS02GT, so we need to use CLPEF instead of CLSR.
This change does not affect to S25x02GT which uses spansion_sr_ready() as S25Hx-T family also supports CLPEF(0x82) as well as CLSR(0x30).
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 2 +- include/linux/mtd/spi-nor.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 3f761b9b9e..20e82aaa65 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -752,7 +752,7 @@ static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) else dev_dbg(nor->dev, "Programming Error occurred\n");
- nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0); + nor->write_reg(nor, SPINOR_OP_CYPRESS_CLPEF, NULL, 0); return -EIO; }
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index ebe38306a1..8a94e12037 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -180,6 +180,7 @@ /* For Cypress flash. */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ +#define SPINOR_OP_CYPRESS_CLPEF 0x82 /* Clear P/E err flag */ #define SPINOR_REG_CYPRESS_ARCFN 0x00000006 #define SPINOR_REG_CYPRESS_STR1V 0x00800000 #define SPINOR_REG_CYPRESS_CFR1V 0x00800002

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Infineon(Cypress) S28Hx-T family does not support legacy CLSR(0x30) opcode. Instead, it supports CLPEF(0x82) which has the same functionality as CLSR. spansion_sr_ready() is for multi-die package parts including S28HS02GT, so we need to use CLPEF instead of CLSR.
This change does not affect to S25x02GT which uses spansion_sr_ready() as S25Hx-T family also supports CLPEF(0x82) as well as CLSR(0x30).
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s25_mdp_ready() handles status polling for multi-die package parts that requires to read and check status register for each die. To support S28HS02GT(dual-die package with Octal DTR support), rename function and use nor->rdsr_dummy in octal DTR mode.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 20e82aaa65..fe5579db4d 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3340,13 +3340,13 @@ static struct spi_nor_fixups s25fs_s_fixups = { .post_sfdp = s25fs_s_post_sfdp_fixup, };
-static int s25_mdp_ready(struct spi_nor *nor) +static int s25_s28_mdp_ready(struct spi_nor *nor) { u32 addr; int ret;
for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { - ret = spansion_sr_ready(nor, addr, 0); + ret = spansion_sr_ready(nor, addr, nor->rdsr_dummy); if (!ret) return ret; } @@ -3416,7 +3416,7 @@ static int s25_setup(struct spi_nor *nor, const struct flash_info *info, * all dies' status via read any register. */ if (nor->mtd.size > SZ_128M) - nor->ready = s25_mdp_ready; + nor->ready = s25_s28_mdp_ready;
return spi_nor_default_setup(nor, info, params); }

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s25_mdp_ready() handles status polling for multi-die package parts that requires to read and check status register for each die. To support S28HS02GT(dual-die package with Octal DTR support), rename function and use nor->rdsr_dummy in octal DTR mode.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s28hx_t_setup() only checks sector layout setting. To support multi-die package parts like S28HS02GT, it needs to check device size and assign ready() hook for multi-die package parts. These are covered in s25_setup() so we can consolidate s28hx_t_setup() and s25_setup() into one named s25_s28_setup().
spi_nor_wait_till_ready() at the beginning of s28hx_t_setup() can be removed since there is no op that makes device busy state before setup.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 41 ++++------------------------------ 1 file changed, 4 insertions(+), 37 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index fe5579db4d..0bc43d3d21 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3375,8 +3375,8 @@ static int s25_s28_erase_non_uniform(struct spi_nor *nor, loff_t addr) SZ_128K); }
-static int s25_setup(struct spi_nor *nor, const struct flash_info *info, - const struct spi_nor_flash_parameter *params) +static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) { int ret; u8 cr; @@ -3423,7 +3423,7 @@ static int s25_setup(struct spi_nor *nor, const struct flash_info *info,
static void s25_default_init(struct spi_nor *nor) { - nor->setup = s25_setup; + nor->setup = s25_s28_setup; }
static int s25_post_bfpt_fixup(struct spi_nor *nor, @@ -3582,43 +3582,10 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) return 0; }
-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; - u8 addr_width = 3; - int ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - /* - * Check CFR3V to check if non-uniform sector mode is selected. If it - * is, set the erase hook to the non-uniform erase procedure. - */ - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, - SPINOR_REG_CYPRESS_CFR3V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, &buf, 1)); - - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - if (!(buf & SPINOR_REG_CYPRESS_CFR3_UNISECT)) - nor->erase = s25_s28_erase_non_uniform; - - return spi_nor_default_setup(nor, info, params); -} - static void s28hx_t_default_init(struct spi_nor *nor) { nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; - nor->setup = s28hx_t_setup; + nor->setup = s25_s28_setup; }
static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor,

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s28hx_t_setup() only checks sector layout setting. To support multi-die package parts like S28HS02GT, it needs to check device size and assign ready() hook for multi-die package parts. These are covered in s25_setup() so we can consolidate s28hx_t_setup() and s25_setup() into one named s25_s28_setup().
spi_nor_wait_till_ready() at the beginning of s28hx_t_setup() can be removed since there is no op that makes device busy state before setup.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s28hx_t_post_bfpt_fixup() fixes erase opcode, erase size, and page size. s25_post_bfpt_fixup() is doing same thing including multi-die support. We can consolidate s28hx_t_post_bfpt_fixup() and s25_post_bfpt_fixup() into one named s25_s28_post_bfpt_fixup().
In s25_s28_post_bfpt_fixup(), set_4byte() is called to force the device to be 4-byte addressing mode. In S28HS02GT datasheet, the B7 opcode is missing but it works actually (confirmed).
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 52 ++++------------------------------ 1 file changed, 6 insertions(+), 46 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 0bc43d3d21..22b5999a87 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3426,10 +3426,10 @@ static void s25_default_init(struct spi_nor *nor) nor->setup = s25_s28_setup; }
-static int s25_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *header, - const struct sfdp_bfpt *bfpt, - struct spi_nor_flash_parameter *params) +static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) { int ret; u32 addr; @@ -3503,7 +3503,7 @@ static void s25_post_sfdp_fixup(struct spi_nor *nor,
static struct spi_nor_fixups s25_fixups = { .default_init = s25_default_init, - .post_bfpt = s25_post_bfpt_fixup, + .post_bfpt = s25_s28_post_bfpt_fixup, .post_sfdp = s25_post_sfdp_fixup, };
@@ -3619,50 +3619,10 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, params->rdsr_addr_nbytes = 4; }
-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; - u8 addr_width = 3; - int ret; - - /* - * The BFPT table advertises a 512B page size but the page size is - * actually configurable (with the default being 256B). Read from - * CFR3V[4] and set the correct size. - */ - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR3V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) - return ret; - - if (buf & SPINOR_REG_CYPRESS_CFR3_PGSZ) - params->page_size = 512; - else - params->page_size = 256; - - /* - * The BFPT advertises that it supports 4k erases, and the datasheet - * says the same. But 4k erases did not work when testing. So, use 256k - * erases for now. - */ - nor->erase_opcode = SPINOR_OP_SE_4B; - nor->mtd.erasesize = 0x40000; - - return 0; -} - 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, + .post_bfpt = s25_s28_post_bfpt_fixup, }; #endif /* CONFIG_SPI_FLASH_S28HX_T */

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
s28hx_t_post_bfpt_fixup() fixes erase opcode, erase size, and page size. s25_post_bfpt_fixup() is doing same thing including multi-die support. We can consolidate s28hx_t_post_bfpt_fixup() and s25_post_bfpt_fixup() into one named s25_s28_post_bfpt_fixup().
In s25_s28_post_bfpt_fixup(), set_4byte() is called to force the device to be 4-byte addressing mode. In S28HS02GT datasheet, the B7 opcode is missing but it works actually (confirmed).
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Enabling Octal DTR mode in multi-die package parts requires reister setup for each die. That can be done by simple for-loop. write_enable() takes effect to all die at once so we can call it before the loop. Besides we can replace spi_mem_exec_op() calls with spansion_read/write_any_reg(). And finally, we must mask CFR2V[7:4] when changing dummy cycles, as CFR2V[7] indicates current addressing mode and that should be 1 (4-byte address mode) for multi-die package parts.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 54 +++++++++++++++++----------------- include/linux/mtd/spi-nor.h | 1 + 2 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 22b5999a87..860b11fd95 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3535,48 +3535,48 @@ static struct spi_nor_fixups s25fl256l_fixups = { */ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) { - struct spi_mem_op op; + u32 addr; u8 buf; - u8 addr_width = 3; int ret;
- /* Use 24 dummy cycles for memory array reads. */ ret = write_enable(nor); if (ret) return ret;
- buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; - op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR2V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) { - dev_warn(nor->dev, - "failed to set default memory latency value: %d\n", - ret); - return ret; - } - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; + /* Use 24 dummy cycles for memory array reads. */ + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_read_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR2V, 0, + &buf); + if (ret) + return ret;
+ buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; + buf |= SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; + ret = spansion_write_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR2V, + buf); + if (ret) { + dev_warn(nor->dev, "failed to set default memory latency value: %d\n", ret); + return ret; + } + } nor->read_dummy = 24;
- /* Set the octal and DTR enable bits. */ ret = write_enable(nor); if (ret) return ret;
+ /* Set the octal and DTR enable bits. */ buf = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; - op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR5V, 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, &buf, 1)); - ret = spi_mem_exec_op(nor->spi, &op); - if (ret) { - dev_warn(nor->dev, "Failed to enable octal DTR mode\n"); - return ret; + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_write_any_reg(nor, + addr + SPINOR_REG_CYPRESS_CFR5V, + buf); + if (ret) { + dev_warn(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } }
return 0; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 8a94e12037..d1dbf3eadb 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -185,6 +185,7 @@ #define SPINOR_REG_CYPRESS_STR1V 0x00800000 #define SPINOR_REG_CYPRESS_CFR1V 0x00800002 #define SPINOR_REG_CYPRESS_CFR2V 0x00800003 +#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK GENMASK(3, 0) #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR3V 0x00800004 #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */

On Fri, Dec 22, 2023 at 11:16 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Enabling Octal DTR mode in multi-die package parts requires reister setup for each die. That can be done by simple for-loop. write_enable() takes effect to all die at once so we can call it before the loop. Besides we can replace spi_mem_exec_op() calls with spansion_read/write_any_reg(). And finally, we must mask CFR2V[7:4] when changing dummy cycles, as CFR2V[7] indicates current addressing mode and that should be 1 (4-byte address mode) for multi-die package parts.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Infineon(Cypress) S28HS02GT is 1.8V, 2Gb (256MB) NOR Flash memory with Octal interface. It is a dual-die package parts and has same features with existing S28 series.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-ids.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index f86e7ff8e5..949ceee375 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -370,6 +370,7 @@ const struct flash_info spi_nor_ids[] = { { 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) }, + { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ) }, #endif #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */

Hi!
On Dec 22, 2023 at 14:46:06 +0900, tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Infineon(Cypress) S28HS02GT is 1.8V, 2Gb (256MB) NOR Flash memory with Octal interface. It is a dual-die package parts and has same features with existing S28 series.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
drivers/mtd/spi/spi-nor-ids.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index f86e7ff8e5..949ceee375 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -370,6 +370,7 @@ const struct flash_info spi_nor_ids[] = { { 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) },
- { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ) },
Reviewed-by: Dhruva Gole d-gole@ti.com
#endif #endif
#ifdef CONFIG_SPI_FLASH_SST /* SST */
2.34.1

On Fri, Dec 22, 2023 at 11:17 AM tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Infineon(Cypress) S28HS02GT is 1.8V, 2Gb (256MB) NOR Flash memory with Octal interface. It is a dual-die package parts and has same features with existing S28 series.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Reviewed-by: Jagan Teki jagan@amarulasolutions.com
participants (3)
-
Dhruva Gole
-
Jagan Teki
-
tkuw584924@gmail.com