[PATCH 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.
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 | 220 +++++++++++++-------------------- drivers/mtd/spi/spi-nor-ids.c | 1 + include/linux/mtd/spi-nor.h | 14 +-- 3 files changed, 89 insertions(+), 146 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 | 22 ++++++++++++---------- include/linux/mtd/spi-nor.h | 11 +++-------- 2 files changed, 15 insertions(+), 18 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 2c3116ee5300..74ac1fc8c41a 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -330,7 +330,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)); @@ -341,7 +341,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)); @@ -712,7 +712,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;
@@ -1820,7 +1820,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; @@ -3249,7 +3249,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;
@@ -3263,10 +3264,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;
/* @@ -3327,12 +3328,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 2861b73edbce..f9a55c8e740c 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

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 74ac1fc8c41a..2f0f24a41ee9 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3227,7 +3227,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, @@ -3268,7 +3268,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 @@ -3441,13 +3441,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) { @@ -3476,7 +3469,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 f9a55c8e740c..ebe38306a1d2 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

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 2f0f24a41ee9..b7f0f3343dd4 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -330,12 +330,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)

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 b7f0f3343dd4..0e4498d6f59e 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -750,7 +750,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 ebe38306a1d2..8a94e1203724 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

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 0e4498d6f59e..3e347a3be38b 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3223,13 +3223,13 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, /* Use ID byte 4 to distinguish S25FS256T and S25Hx-T */ #define S25FS256T_ID4 (0x08)
-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; } @@ -3299,7 +3299,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); }

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 3e347a3be38b..06cd2ff4d62b 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3258,8 +3258,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; @@ -3306,7 +3306,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, @@ -3465,43 +3465,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,

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 06cd2ff4d62b..d9b6bdc23892 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3309,10 +3309,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; @@ -3386,7 +3386,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, };
@@ -3502,50 +3502,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 */

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 d9b6bdc23892..4b0485b54668 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3418,48 +3418,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 8a94e1203724..d1dbf3eadbf7 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. */

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 a862fbd707b3..7ad2a9306c31 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -301,6 +301,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 */
participants (1)
-
tkuw584924@gmail.com