[PATCH v3 0/7] mtd: spi-nor: Add support for Cypress s25hl-t/s25hs-t

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI. The datasheet can be found in https://community.cypress.com/docs/DOC-15165 Tested on Xilinx Zynq-7000 FPGA board.
Takahiro Kuwano (7): mtd: spi-nor: Add Cypress manufacturer ID mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t mtd: spi-nor: Add support for volatile QE bit mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte mtd: spi-nor-core: Add overlaid sector erase feature mtd: spi-nor-core: Add fixups for Cypress s25hl-t/s25hs-t mtd: spi-nor-tiny: Add fixups for Cypress s25hl-t/s25hs-t
drivers/mtd/spi/spi-nor-core.c | 178 +++++++++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-ids.c | 24 +++++ drivers/mtd/spi/spi-nor-tiny.c | 73 ++++++++++++++ include/linux/mtd/spi-nor.h | 3 + 4 files changed, 278 insertions(+)
--- Changes since v3: - Split into multiple patches
Changes since v2: - Fixed typo in comment for spansion_overlaid_erase() - Fixed expressions for addr and len check in spansion_overlaid_erase() - Added device ID check to make the changes effective for S25 only - Added nor->setup() and fixup hooks based on the following patches https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-7-p.yad... https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.yad... https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.yad...

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
This patch adds Cypress manufacturer ID (34h) definition.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- include/linux/mtd/spi-nor.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 5842e9d6ee..89e7a4fdcd 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -27,6 +27,7 @@ #define SNOR_MFR_SPANSION CFI_MFR_AMD #define SNOR_MFR_SST CFI_MFR_SST #define SNOR_MFR_WINBOND 0xef /* Also used by some Spansion */ +#define SNOR_MFR_CYPRESS 0x34
/* * Note on opcode nomenclature: some opcodes have a format like

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI. The datasheet can be found in https://community.cypress.com/docs/DOC-15165
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-ids.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index bc9d4f7e9f..0cdafe4254 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -216,6 +216,30 @@ const struct flash_info spi_nor_ids[] = { { INFO("s25fl208k", 0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, { INFO("s25fl064l", 0x016017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { INFO("s25fl128l", 0x016018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + + /* S25HL/HS-T (Semper Flash with Quad SPI) Family has overlaid 4KB + * sectors at top and/or bottom, depending on the device configuration. + * To support this, an erase hook makes overlaid sectors appear as + * uniform sectors. + */ + { INFO6("s25hl256t", 0x342a19, 0x0f0390, 256 * 1024, 128, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hl512t", 0x342a1a, 0x0f0390, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hl01gt", 0x342a1b, 0x0f0390, 256 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs256t", 0x342b19, 0x0f0390, 256 * 1024, 128, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs512t", 0x342b1a, 0x0f0390, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, + { INFO6("s25hs01gt", 0x342b1b, 0x0f0390, 256 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | + USE_CLSR) }, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ /* SST -- large erase sizes are "overlays", "sectors" are 4K */

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Some of Spansion/Cypress chips support volatile version of configuration registers and it is recommended to update volatile registers in the field application due to a risk of the non-volatile registers corruption by power interrupt. This patch adds a function to set Quad Enable bit in CFR1 volatile.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 54 +++++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-tiny.c | 63 ++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 2 ++ 3 files changed, 119 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 34c15f1561..9a271841ab 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1551,6 +1551,60 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) return 0; }
+/** + * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. + * @nor: pointer to a 'struct spi_nor' + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable_volatile(struct spi_nor *nor) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1), + SPI_MEM_OP_ADDR(nor->addr_width, + SPINOR_REG_ADDR_CFR1V, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, NULL, 1)); + u8 cr; + int ret; + + /* Check current Quad Enable bit value. */ + ret = read_cr(nor); + if (ret < 0) { + dev_dbg(nor->dev, + "error while reading configuration register\n"); + return -EINVAL; + } + + if (ret & CR_QUAD_EN_SPAN) + return 0; + + cr = ret | CR_QUAD_EN_SPAN; + + write_enable(nor); + + ret = spi_nor_read_write_reg(nor, &op, &cr); + + if (ret < 0) { + dev_dbg(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* Read back and check it. */ + ret = read_cr(nor); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_dbg(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + #if CONFIG_IS_ENABLED(SPI_FLASH_SFDP_SUPPORT) /** * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register. diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 5cc2b7d996..1326f028a6 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -555,6 +555,69 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) } #endif /* CONFIG_SPI_FLASH_SPANSION */
+#ifdef CONFIG_SPI_FLASH_SPANSION +/** + * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. + * @nor: pointer to a 'struct spi_nor' + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable_volatile(struct spi_nor *nor) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_ADDR_CFR1V, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, NULL, 1)); + u8 cr; + int ret; + + /* Check current Quad Enable bit value. */ + ret = read_cr(nor); + if (ret < 0) { + dev_dbg(nor->dev, + "error while reading configuration register\n"); + return -EINVAL; + } + + if (ret & CR_QUAD_EN_SPAN) + return 0; + + cr = ret | CR_QUAD_EN_SPAN; + + /* Use 4-byte address for WRAR */ + ret = spi_nor_write_reg(nor, SPINOR_OP_EN4B, NULL, 0); + if (ret < 0) { + dev_dbg(nor->dev, + "error while enabling 4-byte address\n"); + return ret; + } + + write_enable(nor); + + ret = spi_nor_read_write_reg(nor, &op, &cr); + + if (ret < 0) { + dev_dbg(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* Read back and check it. */ + ret = read_cr(nor); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_dbg(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} +#endif + static void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 89e7a4fdcd..9fb4c8521d 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -121,6 +121,8 @@ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ #define SPINOR_OP_BRRD 0x16 /* Bank register read */ #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ +#define SPINOR_OP_WRAR 0x71 /* Write any register */ +#define SPINOR_REG_ADDR_CFR1V 0x00800002
/* Used for Micron flashes only. */ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Cypress chips support SPINOR_OP_EN4B(B7h)/SPINOR_OP_EX4B(E9h) to enable/disable 4-byte addressing mode.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- 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 9a271841ab..6553a7f211 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -467,6 +467,7 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, case SNOR_MFR_ISSI: case SNOR_MFR_MACRONIX: case SNOR_MFR_WINBOND: + case SNOR_MFR_CYPRESS: if (need_wren) write_enable(nor);

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Some of Spansion/Cypress chips have overlaid 4KB sectors at top and/or bottom, depending on the device configuration, while U-Boot supports uniform sector layout only. This patch adds an erase hook that emulates uniform sector layout.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-core.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 6553a7f211..042da329da 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -732,6 +732,54 @@ erase_err: return ret; }
+#ifdef CONFIG_SPI_FLASH_SPANSION +/* + * Erase for Spansion/Cypress Flash devices that has overlaid 4KB sectors at + * the top and/or bottom. + */ +static int spansion_overlaid_erase(struct mtd_info *mtd, + struct erase_info *instr) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct erase_info instr_4k; + u8 opcode; + u32 erasesize; + int ret; + + /* Perform default erase operation (non-overlaid portion is erased) */ + ret = spi_nor_erase(mtd, instr); + if (ret) + return ret; + + /* Backup default erase opcode and size */ + opcode = nor->erase_opcode; + erasesize = mtd->erasesize; + + /* + * Erase 4KB sectors. Use the possible max length of 4KB sector region. + * The Flash just ignores the command if the address is not configured + * as 4KB sector and reports ready status immediately. + */ + instr_4k.len = SZ_128K; + nor->erase_opcode = SPINOR_OP_BE_4K_4B; + mtd->erasesize = SZ_4K; + if (instr->addr == 0) { + instr_4k.addr = 0; + ret = spi_nor_erase(mtd, &instr_4k); + } + if (!ret && instr->addr + instr->len == mtd->size) { + instr_4k.addr = mtd->size - instr_4k.len; + ret = spi_nor_erase(mtd, &instr_4k); + } + + /* Restore erase opcode and size */ + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + + return ret; +} +#endif + #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) /* Write status register and ensure bits in mask match written values */ static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Add nor->setup() and fixup hooks for volatile QE bit, overlaid erase, spi_nor_flash_parameter and mtd_info.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com ---
Depends on the following patches: https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-7-p.yad... https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.yad... https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.yad...
drivers/mtd/spi/spi-nor-core.c | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 042da329da..fbde21a526 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2592,8 +2592,83 @@ static int spi_nor_init(struct spi_nor *nor) return 0; }
+#ifdef CONFIG_SPI_FLASH_SPANSION +static int s25hx_t_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params, + const struct spi_nor_hwcaps *hwcaps) +{ +#ifdef CONFIG_SPI_FLASH_BAR + return -ENOTSUPP; /* Bank Address Register is not supported */ +#endif + /* + * The Cypress Semper family has transparent ECC. To preserve + * ECC enabled, multi-pass programming within the same 16-byte + * ECC data unit needs to be avoided. Set writesize to the page + * size and remove the MTD_BIT_WRITEABLE flag in mtd_info to + * prevent multi-pass programming. + */ + nor->mtd.writesize = params->page_size; + nor->mtd.flags &= ~MTD_BIT_WRITEABLE; + + /* Emulate uniform sector architecure by this erase hook*/ + nor->mtd._erase = spansion_overlaid_erase; + /* Enter 4-byte addressing mode for WRAR used in quad_enable */ + set_4byte(nor, info, true); + + return spi_nor_default_setup(nor, info, params, hwcaps); +} + +static void s25hx_t_default_init(struct spi_nor *nor) +{ + nor->setup = s25hx_t_setup; +} + +static int s25hx_t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + /* Default page size is 256-byte, but BFPT reports 512-byte */ + params->page_size = 256; + /* Reset erase size in case it is set to 4K from BFPT */ + nor->mtd.erasesize = 0; + + return 0; +} + +static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* READ_FAST_4B (0Ch) requires mode cycles*/ + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; + /* PP_1_1_4 is not supported */ + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + /* Use volatile register to enable quad */ + params->quad_enable = spansion_quad_enable_volatile; +} + +static struct spi_nor_fixups s25hx_t_fixups = { + .default_init = s25hx_t_default_init, + .post_bfpt = s25hx_t_post_bfpt_fixup, + .post_sfdp = s25hx_t_post_sfdp_fixup, +}; +#endif + static void spi_nor_set_fixups(struct spi_nor *nor) { +#ifdef CONFIG_SPI_FLASH_SPANSION + if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { + switch (nor->info->id[1]) { + case 0x2a: /* S25HL (QSPI, 3.3V) */ + case 0x2b: /* S25HS (QSPI, 1.8V) */ + nor->fixups = &s25hx_t_fixups; + break; + + default: + break; + } + } +#endif }
int spi_nor_scan(struct spi_nor *nor)

From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
Fixes mode clocks for SPINOR_OP_READ_FAST_4B and volatile QE bit in tiny.
Signed-off-by: Takahiro Kuwano Takahiro.Kuwano@infineon.com --- drivers/mtd/spi/spi-nor-tiny.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 1326f028a6..9643bbacd0 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -646,6 +646,11 @@ static int spi_nor_init_params(struct spi_nor *nor, spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST], 0, 8, SPINOR_OP_READ_FAST, SNOR_PROTO_1_1_1); +#ifdef CONFIG_SPI_FLASH_SPANSION + if (JEDEC_MFR(info) == SNOR_MFR_CYPRESS && + (info->id[1] == 0x2a || info->id[1] == 0x2b)) + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; +#endif }
if (info->flags & SPI_NOR_QUAD_READ) { @@ -722,6 +727,11 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, case SNOR_MFR_MACRONIX: err = macronix_quad_enable(nor); break; +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + case SNOR_MFR_CYPRESS: + err = spansion_quad_enable_volatile(nor); + break; #endif case SNOR_MFR_ST: case SNOR_MFR_MICRON:

Hi Jagan,
On 11/4/2020 5:10 PM, tkuw584924@gmail.com wrote:
From: Takahiro Kuwano Takahiro.Kuwano@infineon.com
The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI. The datasheet can be found in https://community.cypress.com/docs/DOC-15165 Tested on Xilinx Zynq-7000 FPGA board.
Takahiro Kuwano (7): mtd: spi-nor: Add Cypress manufacturer ID mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t mtd: spi-nor: Add support for volatile QE bit mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte mtd: spi-nor-core: Add overlaid sector erase feature mtd: spi-nor-core: Add fixups for Cypress s25hl-t/s25hs-t mtd: spi-nor-tiny: Add fixups for Cypress s25hl-t/s25hs-t
drivers/mtd/spi/spi-nor-core.c | 178 +++++++++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-ids.c | 24 +++++ drivers/mtd/spi/spi-nor-tiny.c | 73 ++++++++++++++ include/linux/mtd/spi-nor.h | 3 + 4 files changed, 278 insertions(+)
Changes since v3:
- Split into multiple patches
Changes since v2:
- Fixed typo in comment for spansion_overlaid_erase()
- Fixed expressions for addr and len check in spansion_overlaid_erase()
- Added device ID check to make the changes effective for S25 only
- Added nor->setup() and fixup hooks based on the following patches https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-7-p.yad... https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.yad... https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.yad...
Please let me revise this series. I would like to add 2Gb (dual die package) and 4Gb (quad die package) pats support.
Thanks, Takahiro
participants (2)
-
Kuwano Takahiro
-
tkuw584924@gmail.com