[PATCH v7 00/14] mtd: spi-nor: Add support for Cypress s25hl-t/s25hs-t

2021-04-26 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.

The summary datasheets can be found in the following links.
https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

The full version can be found in the following links (registration
required).
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-Semper-Flash-with-Quad-SPI/ta-p/260789?attachment-id=19522
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-2Gb-MCP-Semper-Flash-with-Quad-SPI/ta-p/260823?attachment-id=29503

Tested on Xilinx Zynq-7000 FPGA board.

Changes since v7:
  - Fixed return type of s25hx_t_erase_non_uniform() to 'int'
  
Changes since v6:
  - Took some patches from Pratyush's series
  - Removed USE_CLSR flag from S25HL02GT and S25HS02GT
  - Defined SPINOR_OP_EX4B_CYPRESS and use it
  - Removed mtd.writesize fixup
  - Added uniform sector check for multi-die package parts
  - Remove spansion_quad_enable_volatile() from tiny
  - Fixed some other minor issues

Changes since v5:
  - Removed 256Mb and 4Gb parts support
  - Fixed register offset issue in spansion_quad_enable_volatile()
  - Added spi_nor_default_ready() and moved existing code into it
  - Separated spansion_sr_read() to new patch
  - Renamed spansion_overlaid_erase() to spansion_non_uniform_erase() and
changed the implementation to issue the proper erase command based on
the address
  - Added s25hx_t_erase_non_uniform()
  - Changed mtd.writesize and mtd.flags in s25hx_t_setup()
  - Fixed page size and erase size issues in s25hx_t_post_bfpt_fixup()

Changes since v4:
  - Added Read/Write Any Register support
  - Added the ->ready() hook to support multi-die package parts
  - Added S25HL02GT/S25HL04GT/S25HS02GT/S25HS04GT support
  
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.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/

Pratyush Yadav (4):
  mtd: spi-nor-core: Add a ->setup() hook
  mtd: spi-nor-core: Move SFDP related declarations to top
  mtd: spi-nor-core: Introduce flash-specific fixup hooks
  mtd: spi-nor-core: allow truncated erases

Takahiro Kuwano (10):
  mtd: spi-nor-core: Add non-uniform erase for Spansion/Cypress
  mtd: spi-nor: Add Cypress manufacturer ID
  mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t
  mtd: spi-nor-core: Add support for Read/Write Any Register
  mtd: spi-nor-core: Add support for volatile QE bit
  mtd: spi-nor-core: Add the ->ready() hook
  mtd: spi-nor-core: Read status by Read Any Register
  mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte
  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 | 723 -
 drivers/mtd/spi/spi-nor-ids.c  |  16 +
 drivers/mtd/spi/spi-nor-tiny.c |  28 +-
 include/linux/mtd/spi-nor.h| 205 +++---
 4 files changed, 700 insertions(+), 272 deletions(-)

-- 
2.25.1



[PATCH v6 14/14] mtd: spi-nor-tiny: Add fixups for Cypress s25hl-t/s25hs-t

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

Fixes mode clocks for SPINOR_OP_READ_FAST_4B in tiny.

Signed-off-by: Takahiro Kuwano 
---
Changes in v6:
  - Remove spansion_quad_enable_volatile() per comment in

https://patchwork.ozlabs.org/project/uboot/patch/a5c3cf1353d9a621379e2fcfefc51fb44c9680c5.1611729896.git.takahiro.kuw...@infineon.com/

Changes in v5:
  - Add a comment about Flash models and respective IDs

 drivers/mtd/spi/spi-nor-tiny.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index 5cc2b7d996..aa2df75c60 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -583,6 +583,12 @@ static int spi_nor_init_params(struct spi_nor *nor,
spi_nor_set_read_settings(>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))
+   /* 0x2a: S25HL (QSPI, 3.3V), 0x2b: S25HS (QSPI, 1.8V) */
+   params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
+#endif
}
 
if (info->flags & SPI_NOR_QUAD_READ) {
-- 
2.25.1



[PATCH v6 13/14] mtd: spi-nor-core: Add fixups for Cypress s25hl-t/s25hs-t

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

The nor->ready() and spansion_sr_ready() introduced earlier in this
series are used for multi-die package parts.

The nor->quad_enable() sets the volatile QE bit on each die.

The nor->erase() is hooked if the device is not configured to uniform
sectors, assuming it has 32 x 4KB sectors overlaid on bottom address.
Other configurations, top and split, are not supported at this point.
Will submit additional patches to support it as needed.

The post_bfpt/sfdp() fixes the params wrongly advertised in SFDP.

Signed-off-by: Takahiro Kuwano 
---
Changes in v6:
  - Remove mtd.writesize fixup
  - Check if uniform sector is selected in multi-die package parts
  - Fix some other minor issues

Changes in v5:
  - Add s25hx_t_erase_non_uniform()
  - Change mtd.writesize and mtd.flags in s25hx_t_setup()
  - Fix page size and erase size issues in s25hx_t_post_bfpt_fixup()
---
 drivers/mtd/spi/spi-nor-core.c | 142 +
 include/linux/mtd/spi-nor.h|   3 +
 2 files changed, 145 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 5e91338ced..2ee1201f6b 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2676,8 +2676,150 @@ static int spi_nor_init(struct spi_nor *nor)
return 0;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+static int s25hx_t_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);
+   if (!ret)
+   return ret;
+   }
+
+   return 1;
+}
+
+static int s25hx_t_quad_enable(struct spi_nor *nor)
+{
+   u32 addr;
+   int ret;
+
+   for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) {
+   ret = spansion_quad_enable_volatile(nor, addr, 0);
+   if (ret)
+   return ret;
+   }
+
+   return 0;
+}
+
+static ssize_t s25hx_t_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,
+ SZ_128K);
+}
+
+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)
+{
+   int ret;
+   u8 cfr3v;
+
+#ifdef CONFIG_SPI_FLASH_BAR
+   return -ENOTSUPP; /* Bank Address Register is not supported */
+#endif
+   /*
+* 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, );
+   if (ret)
+   return ret;
+   if (!(cfr3v & CFR3V_UNHYSA))
+   nor->erase = s25hx_t_erase_non_uniform;
+
+   /*
+* For the multi-die package parts, the ready() hook is needed to check
+* all dies' status via read any register.
+*/
+   if (nor->mtd.size > SZ_128M)
+   nor->ready = s25hx_t_mdp_ready;
+
+   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)
+{
+   int ret;
+   u32 addr;
+   u8 cfr3v;
+
+   /* erase size in case it is set to 4K from BFPT */
+   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 page_size is set to 512B from BFPT, but it actually depends on
+* the configuration register. Look up the CFR3V and determine the
+* page_size. For multi-die package parts, use 512B only when the all
+* 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, );
+   if (ret)
+   return ret;
+
+   if (!(cfr3v & CFR3V_PGMBUF)) {
+   params->page_size = 256;
+   return 0;
+   }
+   }
+   params->page_size = 512;
+
+   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*/
+   

[PATCH v6 12/14] mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

Cypress chips support SPINOR_OP_EN4B(B7h) to enable 4-byte addressing mode.

Cypress chips support B8h to disable 4-byte addressing mode instead of
SPINOR_OP_EX4B(E9h). 

This patch defines new opcode and updates set_4byte() to support
enable/disable 4-byte addressing mode for Cypress chips.

Signed-off-by: Takahiro Kuwano 
---
Changes in v6:
  - Define SPINOR_OP_EX4B_CYPRESS and use it

 drivers/mtd/spi/spi-nor-core.c | 3 +++
 include/linux/mtd/spi-nor.h| 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 296310eb25..5e91338ced 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -516,6 +516,9 @@ static int set_4byte(struct spi_nor *nor, const struct 
flash_info *info,
}
 
return status;
+   case SNOR_MFR_CYPRESS:
+   cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B_CYPRESS;
+   return nor->write_reg(nor, cmd, NULL, 0);
default:
/* Spansion style */
nor->cmd_buf[0] = enable << 7;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 8a187eaf26..0b295c3eec 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -121,6 +121,7 @@
 #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_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  0x0080
-- 
2.25.1



[PATCH v6 11/14] mtd: spi-nor-core: Read status by Read Any Register

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

The spansion_sr_ready() reads status register 1 by Read Any Register
commnad. This function is called from Flash specific hook with die address
and dummy cycles to support multi-die package parts from Spansion/Cypress.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
Changes in v6:
  - No change

Changes in v5:
  - New in v5, separated from another patch
---
 drivers/mtd/spi/spi-nor-core.c | 29 +
 include/linux/mtd/spi-nor.h|  1 +
 2 files changed, 30 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 55e17aace3..296310eb25 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -523,6 +523,35 @@ static int set_4byte(struct spi_nor *nor, const struct 
flash_info *info,
}
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/*
+ * Read status register 1 by using Read Any Register command to support multi
+ * die package parts.
+ */
+static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy)
+{
+   u32 reg_addr = addr_base + SPINOR_REG_ADDR_STR1V;
+   u8 sr;
+   int ret;
+
+   ret = spansion_read_any_reg(nor, reg_addr, dummy, );
+   if (ret < 0)
+   return ret;
+
+   if (sr & (SR_E_ERR | SR_P_ERR)) {
+   if (sr & SR_E_ERR)
+   dev_dbg(nor->dev, "Erase Error occurred\n");
+   else
+   dev_dbg(nor->dev, "Programming Error occurred\n");
+
+   nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
+   return -EIO;
+   }
+
+   return !(sr & SR_WIP);
+}
+#endif
+
 static int spi_nor_sr_ready(struct spi_nor *nor)
 {
int sr = read_sr(nor);
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 2236e36e28..8a187eaf26 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -123,6 +123,7 @@
 #define SPINOR_OP_CLSR 0x30/* Clear status register 1 */
 #define SPINOR_OP_RDAR 0x65/* Read any register */
 #define SPINOR_OP_WRAR 0x71/* Write any register */
+#define SPINOR_REG_ADDR_STR1V  0x0080
 #define SPINOR_REG_ADDR_CFR1V  0x0082
 
 /* Used for Micron flashes only. */
-- 
2.25.1



[PATCH v6 10/14] mtd: spi-nor-core: Add the ->ready() hook

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

For dual/quad die package devices from Spansion/Cypress, the device's
status needs to be checked by reading status registers in all dies, by
using Read Any Register command. To support this, a Flash specific hook
that can overwrite the legacy status check is needed.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
Changes in v6:
  - Rebase and fix commit description
  
Changes in v5:
  - Move spansion_sr_ready() to different patch
  - Move original code in spi_nor_ready() to newly created
spi_nor_default_ready()

 drivers/mtd/spi/spi-nor-core.c | 10 +-
 include/linux/mtd/spi-nor.h|  2 ++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index d731df30a7..55e17aace3 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -567,7 +567,7 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
return fsr & FSR_READY;
 }
 
-static int spi_nor_ready(struct spi_nor *nor)
+static int spi_nor_default_ready(struct spi_nor *nor)
 {
int sr, fsr;
 
@@ -580,6 +580,14 @@ static int spi_nor_ready(struct spi_nor *nor)
return sr && fsr;
 }
 
+static int spi_nor_ready(struct spi_nor *nor)
+{
+   if (nor->ready)
+   return nor->ready(nor);
+
+   return spi_nor_default_ready(nor);
+}
+
 /*
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index de4472da5c..2236e36e28 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -437,6 +437,7 @@ struct spi_flash {
  * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
  * completely locked
  * @quad_enable:   [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @ready: [FLASH-SPECIFIC] check if the flash is ready
  * @priv:  the private data
  */
 struct spi_nor {
@@ -482,6 +483,7 @@ struct spi_nor {
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
+   int (*ready)(struct spi_nor *nor);
 
void *priv;
 /* Compatibility for spi_flash, remove once sf layer is merged with mtd */
-- 
2.25.1



[PATCH v6 09/14] mtd: spi-nor-core: Add support for volatile QE bit

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
Changes in v6:
  - No change

Changes in v5:
  - Fix register address calculation, 'base | offset' -> 'base + offset'

 drivers/mtd/spi/spi-nor-core.c | 53 ++
 include/linux/mtd/spi-nor.h|  1 +
 2 files changed, 54 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 36c1756576..d731df30a7 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1644,6 +1644,59 @@ 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'
+ * @addr_base: base address of register (can be >0 in multi-die parts)
+ * @dummy: number of dummy cycles for register read
+ *
+ * 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, u32 addr_base,
+u8 dummy)
+{
+   u32 addr = addr_base + SPINOR_REG_ADDR_CFR1V;
+
+   u8 cr;
+   int ret;
+
+   /* Check current Quad Enable bit value. */
+   ret = spansion_read_any_reg(nor, addr, dummy, );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while reading configuration register\n");
+   return -EINVAL;
+   }
+
+   if (cr & CR_QUAD_EN_SPAN)
+   return 0;
+
+   cr |= CR_QUAD_EN_SPAN;
+
+   write_enable(nor);
+
+   ret = spansion_write_any_reg(nor, addr, cr);
+
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while writing configuration register\n");
+   return -EINVAL;
+   }
+
+   /* Read back and check it. */
+   ret = spansion_read_any_reg(nor, addr, dummy, );
+   if (ret || !(cr & 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/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index a9b389f2af..de4472da5c 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -123,6 +123,7 @@
 #define SPINOR_OP_CLSR 0x30/* Clear status register 1 */
 #define SPINOR_OP_RDAR 0x65/* Read any register */
 #define SPINOR_OP_WRAR 0x71/* Write any register */
+#define SPINOR_REG_ADDR_CFR1V  0x0082
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_RD_EVCR  0x65/* Read EVCR register */
-- 
2.25.1



[PATCH v6 08/14] mtd: spi-nor-core: Add support for Read/Write Any Register

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

Some of Spansion/Cypress chips support Read/Write Any Register commands.
These commands are mainly used to write volatile registers and access to
the registers in second and subsequent die for multi-die package parts.

The Read Any Register instruction (65h) is followed by register address
and dummy cycles, then the selected register byte is returned.

The Write Any Register instruction (71h) is followed by register address
and register byte to write.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
Changes in v6:
  - No change

Changes in v5:
  - Remove unused defines from spi-nor.h

 drivers/mtd/spi/spi-nor-core.c | 25 +
 include/linux/mtd/spi-nor.h|  2 ++
 2 files changed, 27 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 1b84e389ad..36c1756576 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -212,6 +212,31 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 
opcode, u8 *buf, int len)
return spi_nor_read_write_reg(nor, , buf);
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+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));
+
+   return spi_nor_read_write_reg(nor, , val);
+}
+
+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));
+
+   return spi_nor_read_write_reg(nor, , );
+}
+#endif
+
 static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
 u_char *buf)
 {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 47ce8f5f25..a9b389f2af 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_RDAR 0x65/* Read any register */
+#define SPINOR_OP_WRAR 0x71/* Write any register */
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_RD_EVCR  0x65/* Read EVCR register */
-- 
2.25.1



[PATCH v6 05/14] mtd: spi-nor-core: Add non-uniform erase for Spansion/Cypress

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

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.

The spansion_erase_non_uniform()  erases overlaid 4KB sectors,
non-overlaid portion of normal sector, and remaining normal sectors, by
selecting correct erase command and size based on the address to erase
and size of overlaid portion in parameters. Since different Spansion
flashes can use different opcode for erasing the 4K sectors, the opcode
must be passed in as a parameter based on the flash being used.

Signed-off-by: Takahiro Kuwano 
Signed-off-by: Pratyush Yadav 
[p.ya...@ti.com: Refactor the function to be compatible with nor->erase,
make 4K opcode customizable, call spi_nor_setup_op() before executing
the op.]
[takahiro.kuw...@infineon.com: Remove spi_nor_setup_op() and initialize
op.cmd.buswidth and op.addr.buswidth by 1]
---

Once Pratyush's patch [0] is accepted, I will rebase this series.

[0] 
https://patchwork.ozlabs.org/project/uboot/patch/20210401193133.18129-27-p.ya...@ti.com/

 drivers/mtd/spi/spi-nor-core.c | 59 ++
 1 file changed, 59 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 829ad36903..1b84e389ad 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -739,6 +739,65 @@ erase_err:
return ret;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/**
+ * spansion_erase_non_uniform() - erase non-uniform sectors for 
Spansion/Cypress
+ *chips
+ * @nor:   pointer to a 'struct spi_nor'
+ * @addr:  address of the sector to erase
+ * @opcode_4k: opcode for 4K sector erase
+ * @ovlsz_top: size of overlaid portion at the top address
+ * @ovlsz_btm: size of overlaid portion at the bottom address
+ *
+ * Erase an address range on the nor chip that can contain 4KB sectors overlaid
+ * on top and/or bottom. The appropriate erase opcode and size are chosen by
+ * address to erase and size of overlaid portion.
+ *
+ * Return: number of bytes erased on success, -errno otherwise.
+ */
+static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr,
+ u8 opcode_4k, u32 ovlsz_top,
+ u32 ovlsz_btm)
+{
+   struct spi_mem_op op =
+   SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
+  SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
+  SPI_MEM_OP_NO_DUMMY,
+  SPI_MEM_OP_NO_DATA);
+   struct mtd_info *mtd = >mtd;
+   u32 erasesize;
+   int ret;
+
+   /* 4KB sectors */
+   if (op.addr.val < ovlsz_btm ||
+   op.addr.val >= mtd->size - ovlsz_top) {
+   op.cmd.opcode = opcode_4k;
+   erasesize = SZ_4K;
+
+   /* Non-overlaid portion in the normal sector at the bottom */
+   } else if (op.addr.val == ovlsz_btm) {
+   op.cmd.opcode = nor->erase_opcode;
+   erasesize = mtd->erasesize - ovlsz_btm;
+
+   /* Non-overlaid portion in the normal sector at the top */
+   } else if (op.addr.val == mtd->size - mtd->erasesize) {
+   op.cmd.opcode = nor->erase_opcode;
+   erasesize = mtd->erasesize - ovlsz_top;
+
+   /* Normal sectors */
+   } else {
+   op.cmd.opcode = nor->erase_opcode;
+   erasesize = mtd->erasesize;
+   }
+
+   ret = spi_mem_exec_op(nor->spi, );
+   if (ret)
+   return ret;
+
+   return erasesize;
+}
+#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)
-- 
2.25.1



[PATCH v6 07/14] mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.

https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

The full version can be found in the following links (registration
required).
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-Semper-Flash-with-Quad-SPI/ta-p/260789?attachment-id=19522
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-2Gb-MCP-Semper-Flash-with-Quad-SPI/ta-p/260823?attachment-id=29503

S25HL/HS-T (Semper Flash with Quad SPI) Family has user-configurable
sector architecture. By default, the 512Mb and 1Gb, single-die package
parts are configured to non-uniform that 4KB sectors overlaid on bottom
address. To support this, an erase hook makes overlaid sectors appear as
uniform sectors. The 2Gb, dual-die package parts are configured to uniform
by default.

Tested on Xilinx Zynq-7000 FPGA board.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
Changes in v6:
  - Remove USE_CLSR flag from S25HL02GT and S25HS02GT
  - Remove comment block and update commit description

Changes in v5:
  - Remove 256Mb and 4Gb parts

 drivers/mtd/spi/spi-nor-ids.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 2b57797954..d6f1b7d8a3 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -222,6 +222,22 @@ 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) },
+   { 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("s25hl02gt",  0x342a1c, 0x0f0090, 256 * 1024, 1024,
+   SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+   { 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) },
+   { INFO6("s25hs02gt",  0x342b1c, 0x0f0090, 256 * 1024, 1024,
+   SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 #endif
 #ifdef CONFIG_SPI_FLASH_SST/* SST */
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
-- 
2.25.1



[PATCH v6 03/14] mtd: spi-nor-core: Introduce flash-specific fixup hooks

2021-04-06 Thread tkuw584924
From: Pratyush Yadav 

Sometimes the information in a flash's SFDP tables is wrong. Sometimes
some information just can't be expressed in the SFDP table. So,
introduce the fixup hooks to allow tailoring settings for a specific
flash.

Three hooks are added: default_init, post_sfdp, and post_bfpt. These
allow tweaking the flash settings at different point in the probe
sequence. Since the hooks reside in nor->info, set that value just
before the call to spi_nor_init_params().

The hooks and at what points they are executed mimics Linux's spi-nor
framework. One major difference is that Linux puts the struct
spi_nor_fixups in nor->info. This is not possible in U-Boot because the
spi-nor-ids list is shared between spi-nor-core.c and spi-nor-tiny.c.
Since spi-nor-tiny shouldn't have those fixup hooks populated, add a
separate function that lets flashes populate their fixup hooks.

Signed-off-by: Pratyush Yadav 
---

Taken from Pratyush's series:
https://patchwork.ozlabs.org/project/uboot/list/?series=237040=*

 drivers/mtd/spi/spi-nor-core.c | 78 --
 include/linux/mtd/spi-nor.h|  2 +
 2 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index eb58e9ea09..9f31e6b92a 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -152,6 +152,31 @@ struct sfdp_bfpt {
u32 dwords[BFPT_DWORD_MAX];
 };
 
+/**
+ * struct spi_nor_fixups - SPI NOR fixup hooks
+ * @default_init: called after default flash parameters init. Used to tweak
+ *flash parameters when information provided by the flash_info
+ *table is incomplete or wrong.
+ * @post_bfpt: called after the BFPT table has been parsed
+ * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs
+ * that do not support RDSFDP). Typically used to tweak various
+ * parameters that could not be extracted by other means (i.e.
+ * when information provided by the SFDP/flash_info tables are
+ * incomplete or wrong).
+ *
+ * Those hooks can be used to tweak the SPI NOR configuration when the SFDP
+ * table is broken or not available.
+ */
+struct spi_nor_fixups {
+   void (*default_init)(struct spi_nor *nor);
+   int (*post_bfpt)(struct spi_nor *nor,
+const struct sfdp_parameter_header *bfpt_header,
+const struct sfdp_bfpt *bfpt,
+struct spi_nor_flash_parameter *params);
+   void (*post_sfdp)(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params);
+};
+
 static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
*op, void *buf)
 {
@@ -1751,6 +1776,18 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = 
{
 
 static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
 
+static int
+spi_nor_post_bfpt_fixups(struct spi_nor *nor,
+const struct sfdp_parameter_header *bfpt_header,
+const struct sfdp_bfpt *bfpt,
+struct spi_nor_flash_parameter *params)
+{
+   if (nor->fixups && nor->fixups->post_bfpt)
+   return nor->fixups->post_bfpt(nor, bfpt_header, bfpt, params);
+
+   return 0;
+}
+
 /**
  * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
  * @nor:   pointer to a 'struct spi_nor'
@@ -1889,7 +1926,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 
/* Stop here if not JESD216 rev A or later. */
if (bfpt_header->length < BFPT_DWORD_MAX)
-   return 0;
+   return spi_nor_post_bfpt_fixups(nor, bfpt_header, ,
+   params);
 
/* Page size: this field specifies 'N' so the page size = 2^N bytes. */
params->page_size = bfpt.dwords[BFPT_DWORD(11)];
@@ -1922,7 +1960,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return -EINVAL;
}
 
-   return 0;
+   return spi_nor_post_bfpt_fixups(nor, bfpt_header, , params);
 }
 
 /**
@@ -2085,6 +2123,29 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 }
 #endif /* SPI_FLASH_SFDP_SUPPORT */
 
+/**
+ * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings
+ * after SFDP has been parsed (is also called for SPI NORs that do not
+ * support RDSFDP).
+ * @nor:   pointer to a 'struct spi_nor'
+ *
+ * Typically used to tweak various parameters that could not be extracted by
+ * other means (i.e. when information provided by the SFDP/flash_info tables
+ * are incomplete or wrong).
+ */
+static void spi_nor_post_sfdp_fixups(struct spi_nor *nor,
+struct spi_nor_flash_parameter *params)
+{
+   if (nor->fixups && nor->fixups->post_sfdp)
+   nor->fixups->post_sfdp(nor, params);
+}
+
+static void spi_nor_default_init_fixups(struct spi_nor *nor)

[PATCH v6 06/14] mtd: spi-nor: Add Cypress manufacturer ID

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

This patch adds Cypress manufacturer ID (34h) definition.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
 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 b2e9e0895b..47ce8f5f25 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
-- 
2.25.1



[PATCH v6 04/14] mtd: spi-nor-core: allow truncated erases

2021-04-06 Thread tkuw584924
From: Pratyush Yadav 

On devices with non-uniform sector sizes like Spansion S25 or S28 family
of flashes the sector under erase does not necessarily have to be
mtd->erasesize bytes long. For example, on S28 flashes the first 128 KiB
region is composed of 32 4 KiB sectors, then a 128 KiB sector, and then
256 KiB sectors till the end.

Let the flash-specific erase functions erase less than the requested
length in case of the 4 or 128 KiB sectors and report the number of
bytes erased back to the calling function.

Signed-off-by: Pratyush Yadav 
[takahiro.kuw...@infineon.com: base on master to exclude Octal/DTR
related changes]
Signed-off-by: Takahiro Kuwano 
---

Pratyush's original patch [0] depends on the other changes in his
series. Once his patch is accepted, I will rebase this series.

[0] 
https://patchwork.ozlabs.org/project/uboot/patch/20210401193133.18129-26-p.ya...@ti.com/

 drivers/mtd/spi/spi-nor-core.c | 16 +++-
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 9f31e6b92a..829ad36903 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -660,7 +660,8 @@ static int read_bar(struct spi_nor *nor, const struct 
flash_info *info)
 #endif
 
 /*
- * Initiate the erasure of a single sector
+ * Initiate the erasure of a single sector. Returns the number of bytes erased
+ * on success, a negative error code on error.
  */
 static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 {
@@ -669,6 +670,7 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 
addr)
   SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
   SPI_MEM_OP_NO_DUMMY,
   SPI_MEM_OP_NO_DATA);
+   int ret;
 
if (nor->erase)
return nor->erase(nor, addr);
@@ -677,7 +679,11 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 
addr)
 * Default implementation, if driver doesn't have a specialized HW
 * control
 */
-   return spi_mem_exec_op(nor->spi, );
+   ret = spi_mem_exec_op(nor->spi, );
+   if (ret)
+   return ret;
+
+   return nor->mtd.erasesize;
 }
 
 /*
@@ -713,11 +719,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct 
erase_info *instr)
write_enable(nor);
 
ret = spi_nor_erase_sector(nor, addr);
-   if (ret)
+   if (ret < 0)
goto erase_err;
 
-   addr += mtd->erasesize;
-   len -= mtd->erasesize;
+   addr += ret;
+   len -= ret;
 
ret = spi_nor_wait_till_ready(nor);
if (ret)
-- 
2.25.1



[PATCH v6 02/14] mtd: spi-nor-core: Move SFDP related declarations to top

2021-04-06 Thread tkuw584924
From: Pratyush Yadav 

These structures will be used in a later commit inside another structure
definition. Also take the declarations out of the ifdef since they won't
affect the final binary anyway and will be used in a later commit.

Signed-off-by: Pratyush Yadav 
---

Taken from Pratyush's series:
https://patchwork.ozlabs.org/project/uboot/list/?series=237040=*

 drivers/mtd/spi/spi-nor-core.c | 224 -
 1 file changed, 112 insertions(+), 112 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index bda00fa76e..eb58e9ea09 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -40,6 +40,118 @@
 
 #define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ)
 
+struct sfdp_parameter_header {
+   u8  id_lsb;
+   u8  minor;
+   u8  major;
+   u8  length; /* in double words */
+   u8  parameter_table_pointer[3]; /* byte address */
+   u8  id_msb;
+};
+
+#define SFDP_PARAM_HEADER_ID(p)(((p)->id_msb << 8) | (p)->id_lsb)
+#define SFDP_PARAM_HEADER_PTP(p) \
+   (((p)->parameter_table_pointer[2] << 16) | \
+((p)->parameter_table_pointer[1] <<  8) | \
+((p)->parameter_table_pointer[0] <<  0))
+
+#define SFDP_BFPT_ID   0xff00  /* Basic Flash Parameter Table */
+#define SFDP_SECTOR_MAP_ID 0xff81  /* Sector Map Table */
+#define SFDP_SST_ID0x01bf  /* Manufacturer specific Table */
+
+#define SFDP_SIGNATURE 0x50444653U
+#define SFDP_JESD216_MAJOR 1
+#define SFDP_JESD216_MINOR 0
+#define SFDP_JESD216A_MINOR5
+#define SFDP_JESD216B_MINOR6
+
+struct sfdp_header {
+   u32 signature; /* Ox50444653U <=> "SFDP" */
+   u8  minor;
+   u8  major;
+   u8  nph; /* 0-base number of parameter headers */
+   u8  unused;
+
+   /* Basic Flash Parameter Table. */
+   struct sfdp_parameter_headerbfpt_header;
+};
+
+/* Basic Flash Parameter Table */
+
+/*
+ * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
+ * They are indexed from 1 but C arrays are indexed from 0.
+ */
+#define BFPT_DWORD(i)  ((i) - 1)
+#define BFPT_DWORD_MAX 16
+
+/* The first version of JESB216 defined only 9 DWORDs. */
+#define BFPT_DWORD_MAX_JESD216 9
+
+/* 1st DWORD. */
+#define BFPT_DWORD1_FAST_READ_1_1_2BIT(16)
+#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY   (0x0UL << 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4   (0x1UL << 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY   (0x2UL << 17)
+#define BFPT_DWORD1_DTRBIT(19)
+#define BFPT_DWORD1_FAST_READ_1_2_2BIT(20)
+#define BFPT_DWORD1_FAST_READ_1_4_4BIT(21)
+#define BFPT_DWORD1_FAST_READ_1_1_4BIT(22)
+
+/* 5th DWORD. */
+#define BFPT_DWORD5_FAST_READ_2_2_2BIT(0)
+#define BFPT_DWORD5_FAST_READ_4_4_4BIT(4)
+
+/* 11th DWORD. */
+#define BFPT_DWORD11_PAGE_SIZE_SHIFT   4
+#define BFPT_DWORD11_PAGE_SIZE_MASKGENMASK(7, 4)
+
+/* 15th DWORD. */
+
+/*
+ * (from JESD216 rev B)
+ * Quad Enable Requirements (QER):
+ * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
+ * reads based on instruction. DQ3/HOLD# functions are hold during
+ * instruction phase.
+ * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
+ * two data bytes where bit 1 of the second byte is one.
+ * [...]
+ * Writing only one byte to the status register has the side-effect of
+ * clearing status register 2, including the QE bit. The 100b code is
+ * used if writing one byte to the status register does not modify
+ * status register 2.
+ * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
+ * one data byte where bit 6 is one.
+ * [...]
+ * - 011b: QE is bit 7 of status register 2. It is set via Write status
+ * register 2 instruction 3Eh with one data byte where bit 7 is one.
+ * [...]
+ * The status register 2 is read using instruction 3Fh.
+ * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
+ * two data bytes where bit 1 of the second byte is one.
+ * [...]
+ * In contrast to the 001b code, writing one byte to the status
+ * register does not modify status register 2.
+ * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
+ * Read Status instruction 05h. Status register2 is read using
+ * instruction 35h. QE is set via Writ Status instruction 01h with
+ * two data bytes where bit 1 of the second byte is one.
+ * [...]
+ */
+#define BFPT_DWORD15_QER_MASK  GENMASK(22, 

[PATCH v6 01/14] mtd: spi-nor-core: Add a ->setup() hook

2021-04-06 Thread tkuw584924
From: Pratyush Yadav 

nor->setup() can be used by flashes to configure settings in case they
have any peculiarities that can't be easily expressed by the generic
spi-nor framework. This includes things like different opcodes, dummy
cycles, page size, uniform/non-uniform sector sizes, etc.

Move related declarations to avoid forward declarations.

Inspired by the Linux kernel's setup() hook.

Signed-off-by: Pratyush Yadav 
---

Taken from Pratyush's series:
https://patchwork.ozlabs.org/project/uboot/list/?series=237040=*

 drivers/mtd/spi/spi-nor-core.c |  84 +++
 drivers/mtd/spi/spi-nor-tiny.c |  22 
 include/linux/mtd/spi-nor.h| 192 ++---
 3 files changed, 147 insertions(+), 151 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index e0efebc355..bda00fa76e 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1451,71 +1451,6 @@ static int spansion_no_read_cr_quad_enable(struct 
spi_nor *nor)
 #endif /* CONFIG_SPI_FLASH_SFDP_SUPPORT */
 #endif /* CONFIG_SPI_FLASH_SPANSION */
 
-struct spi_nor_read_command {
-   u8  num_mode_clocks;
-   u8  num_wait_states;
-   u8  opcode;
-   enum spi_nor_protocol   proto;
-};
-
-struct spi_nor_pp_command {
-   u8  opcode;
-   enum spi_nor_protocol   proto;
-};
-
-enum spi_nor_read_command_index {
-   SNOR_CMD_READ,
-   SNOR_CMD_READ_FAST,
-   SNOR_CMD_READ_1_1_1_DTR,
-
-   /* Dual SPI */
-   SNOR_CMD_READ_1_1_2,
-   SNOR_CMD_READ_1_2_2,
-   SNOR_CMD_READ_2_2_2,
-   SNOR_CMD_READ_1_2_2_DTR,
-
-   /* Quad SPI */
-   SNOR_CMD_READ_1_1_4,
-   SNOR_CMD_READ_1_4_4,
-   SNOR_CMD_READ_4_4_4,
-   SNOR_CMD_READ_1_4_4_DTR,
-
-   /* Octo SPI */
-   SNOR_CMD_READ_1_1_8,
-   SNOR_CMD_READ_1_8_8,
-   SNOR_CMD_READ_8_8_8,
-   SNOR_CMD_READ_1_8_8_DTR,
-
-   SNOR_CMD_READ_MAX
-};
-
-enum spi_nor_pp_command_index {
-   SNOR_CMD_PP,
-
-   /* Quad SPI */
-   SNOR_CMD_PP_1_1_4,
-   SNOR_CMD_PP_1_4_4,
-   SNOR_CMD_PP_4_4_4,
-
-   /* Octo SPI */
-   SNOR_CMD_PP_1_1_8,
-   SNOR_CMD_PP_1_8_8,
-   SNOR_CMD_PP_8_8_8,
-
-   SNOR_CMD_PP_MAX
-};
-
-struct spi_nor_flash_parameter {
-   u64 size;
-   u32 page_size;
-
-   struct spi_nor_hwcaps   hwcaps;
-   struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
-   struct spi_nor_pp_command   page_programs[SNOR_CMD_PP_MAX];
-
-   int (*quad_enable)(struct spi_nor *nor);
-};
-
 static void
 spi_nor_set_read_settings(struct spi_nor_read_command *read,
  u8 num_mode_clocks,
@@ -2377,9 +2312,10 @@ static int spi_nor_select_erase(struct spi_nor *nor,
return 0;
 }
 
-static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
-const struct spi_nor_flash_parameter *params,
-const struct spi_nor_hwcaps *hwcaps)
+static int spi_nor_default_setup(struct spi_nor *nor,
+const struct flash_info *info,
+const struct spi_nor_flash_parameter *params,
+const struct spi_nor_hwcaps *hwcaps)
 {
u32 ignored_mask, shared_mask;
bool enable_quad_io;
@@ -2438,6 +2374,16 @@ static int spi_nor_setup(struct spi_nor *nor, const 
struct flash_info *info,
return 0;
 }
 
+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+const struct spi_nor_flash_parameter *params,
+const struct spi_nor_hwcaps *hwcaps)
+{
+   if (!nor->setup)
+   return 0;
+
+   return nor->setup(nor, info, params, hwcaps);
+}
+
 static int spi_nor_init(struct spi_nor *nor)
 {
int err;
@@ -2504,6 +2450,8 @@ int spi_nor_scan(struct spi_nor *nor)
nor->read_reg = spi_nor_read_reg;
nor->write_reg = spi_nor_write_reg;
 
+   nor->setup = spi_nor_default_setup;
+
if (spi->mode & SPI_RX_OCTAL) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
 
diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index 07c8c7b82b..5cc2b7d996 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -555,28 +555,6 @@ static int spansion_read_cr_quad_enable(struct spi_nor 
*nor)
 }
 #endif /* CONFIG_SPI_FLASH_SPANSION */
 
-struct spi_nor_read_command {
-   u8  num_mode_clocks;
-   u8  num_wait_states;
-   u8  opcode;
-   enum spi_nor_protocol   proto;
-};
-
-enum spi_nor_read_command_index {
-   SNOR_CMD_READ,
-   SNOR_CMD_READ_FAST,
-
-   /* Quad SPI */
-   SNOR_CMD_READ_1_1_4,
-
-   SNOR_CMD_READ_MAX
-};
-
-struct 

[PATCH v6 00/14] mtd: spi-nor: Add support for Cypress s25hl-t/s25hs-t

2021-04-06 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.

The summary datasheets can be found in the following links.
https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

The full version can be found in the following links (registration
required).
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-Semper-Flash-with-Quad-SPI/ta-p/260789?attachment-id=19522
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-2Gb-MCP-Semper-Flash-with-Quad-SPI/ta-p/260823?attachment-id=29503

Tested on Xilinx Zynq-7000 FPGA board.

Changes since v6:
  - Took some patches from Pratyush's series
  - Removed USE_CLSR flag from S25HL02GT and S25HS02GT
  - Defined SPINOR_OP_EX4B_CYPRESS and use it
  - Removed mtd.writesize fixup
  - Added uniform sector check for multi-die package parts
  - Remove spansion_quad_enable_volatile() from tiny
  - Fixed some other minor issues

Changes since v5:
  - Removed 256Mb and 4Gb parts support
  - Fixed register offset issue in spansion_quad_enable_volatile()
  - Added spi_nor_default_ready() and moved existing code into it
  - Separated spansion_sr_read() to new patch
  - Renamed spansion_overlaid_erase() to spansion_non_uniform_erase() and
changed the implementation to issue the proper erase command based on
the address
  - Added s25hx_t_erase_non_uniform()
  - Changed mtd.writesize and mtd.flags in s25hx_t_setup()
  - Fixed page size and erase size issues in s25hx_t_post_bfpt_fixup()

Changes since v4:
  - Added Read/Write Any Register support
  - Added the ->ready() hook to support multi-die package parts
  - Added S25HL02GT/S25HL04GT/S25HS02GT/S25HS04GT support
  
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.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/

Pratyush Yadav (4):
  mtd: spi-nor-core: Add a ->setup() hook
  mtd: spi-nor-core: Move SFDP related declarations to top
  mtd: spi-nor-core: Introduce flash-specific fixup hooks
  mtd: spi-nor-core: allow truncated erases

Takahiro Kuwano (10):
  mtd: spi-nor-core: Add non-uniform erase for Spansion/Cypress
  mtd: spi-nor: Add Cypress manufacturer ID
  mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t
  mtd: spi-nor-core: Add support for Read/Write Any  Register
  mtd: spi-nor-core: Add support for volatile QE bit
  mtd: spi-nor-core: Add the ->ready() hook
  mtd: spi-nor-core: Read status by Read Any Register
  mtd: spi-nor-core: Add Cypress manufacturer ID in  set_4byte
  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 | 723 -
 drivers/mtd/spi/spi-nor-ids.c  |  16 +
 drivers/mtd/spi/spi-nor-tiny.c |  28 +-
 include/linux/mtd/spi-nor.h| 205 +++---
 4 files changed, 700 insertions(+), 272 deletions(-)

-- 
2.25.1



[PATCH v5 10/10] mtd: spi-nor-tiny: Add fixups for Cypress s25hl-t/s25hs-t

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

Fixes mode clocks for SPINOR_OP_READ_FAST_4B and volatile QE bit in tiny.
The volatile QE bit function, spansion_quad_enable_volatile() supports
dual/quad die package parts, by taking 'die_size' parameter that is used
to iterate register update for all dies in the device.

Signed-off-by: Takahiro Kuwano 
---
Changes in v5:
  - Add a comment about Flash models and respective IDs

 drivers/mtd/spi/spi-nor-tiny.c | 90 ++
 1 file changed, 90 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index 5cc2b7d996..66e4c99cc6 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -555,6 +555,85 @@ 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'
+ * @die_size:  maximum number of bytes per die ('mtd.size' > 'die_size' in
+ *  multi die package parts).
+ * @dummy: number of dummy cycles for register read
+ *
+ * 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, u32 die_size,
+u8 dummy)
+{
+   struct spi_mem_op op =
+   SPI_MEM_OP(SPI_MEM_OP_CMD(0, 1),
+  SPI_MEM_OP_ADDR(4, 0, 1),
+  SPI_MEM_OP_DUMMY(0, 1),
+  SPI_MEM_OP_DATA_IN(1, NULL, 1));
+   u32 addr;
+   u8 cr;
+   int ret;
+
+   /* Use 4-byte address for RDAR/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;
+   }
+
+   for (addr = 0; addr < nor->mtd.size; addr += die_size) {
+   op.addr.val = addr + SPINOR_REG_ADDR_CFR1V;
+
+   /* Check current Quad Enable bit value. */
+   op.cmd.opcode = SPINOR_OP_RDAR;
+   op.dummy.nbytes = dummy / 8;
+   op.data.dir = SPI_MEM_DATA_IN;
+   ret = spi_nor_read_write_reg(nor, , );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while reading configuration register\n");
+   return -EINVAL;
+   }
+
+   if (cr & CR_QUAD_EN_SPAN)
+   return 0;
+
+   /* Write new value. */
+   cr |= CR_QUAD_EN_SPAN;
+   op.cmd.opcode = SPINOR_OP_WRAR;
+   op.dummy.nbytes = 0;
+   op.data.dir = SPI_MEM_DATA_OUT;
+   write_enable(nor);
+   ret = spi_nor_read_write_reg(nor, , );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while writing configuration register\n");
+   return -EINVAL;
+   }
+
+   /* Read back and check it. */
+   op.cmd.opcode = SPINOR_OP_RDAR;
+   op.dummy.nbytes = dummy / 8;
+   op.data.dir = SPI_MEM_DATA_IN;
+   ret = spi_nor_read_write_reg(nor, , );
+   if (ret || !(cr & 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,
@@ -583,6 +662,12 @@ static int spi_nor_init_params(struct spi_nor *nor,
spi_nor_set_read_settings(>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))
+   /* 0x2a: S25HL (QSPI, 3.3V), 0x2b: S25HS (QSPI, 1.8V) */
+   params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
+#endif
}
 
if (info->flags & SPI_NOR_QUAD_READ) {
@@ -659,6 +744,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, SZ_128M, 0);
+   

[PATCH v5 09/10] mtd: spi-nor-core: Add fixups for Cypress s25hl-t/s25hs-t

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

This patch adds Flash specific fixups and hooks for Cypress
S25HL-T/S25HS-T family, based on the features introduced in [0][1][2].

The nor->ready() and spansion_sr_ready() introduced in #5 and #6 in this
series are used for multi-die package parts.

The nor->quad_enable() sets the volatile QE bit on each die.

The mtd._erase() is hooked if the device is single-die package and not
configured to uniform sectors, assuming it is in factory default
configuration that has 32 x 4KB sectors overlaid on bottom address.
Other configurations, top and split, are not supported at this point.
Will submit additional patches to support it as needed.

The post_bfpt/sfdp() fixes the params wrongly advertised in SFDP.

[0] 
https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-7-p.ya...@ti.com/
[1] 
https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/
[2] 
https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/

Signed-off-by: Takahiro Kuwano 
---
Changes in v5:
  - Add s25hx_t_erase_non_uniform()
  - Change mtd.writesize and mtd.flags in s25hx_t_setup()
  - Fix page size and erase size issues in s25hx_t_post_bfpt_fixup()

 drivers/mtd/spi/spi-nor-core.c | 155 +
 include/linux/mtd/spi-nor.h|   3 +
 2 files changed, 158 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 8d63681cb3..315e26ab27 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2677,8 +2677,163 @@ static int spi_nor_init(struct spi_nor *nor)
return 0;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+static int s25hx_t_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);
+   if (ret != 1)
+   return ret;
+   }
+
+   return 1;
+}
+
+static int s25hx_t_quad_enable(struct spi_nor *nor)
+{
+   u32 addr;
+   int ret;
+
+   for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) {
+   ret = spansion_quad_enable_volatile(nor, addr, 0);
+   if (ret)
+   return ret;
+   }
+
+   return 0;
+}
+
+static int s25hx_t_erase_non_uniform(struct mtd_info *mtd,
+struct erase_info *instr)
+{
+   /* Support factory default configuration (32 x 4KB sectors at bottom) */
+   return spansion_erase_non_uniform(mtd, instr, 0, SZ_128K);
+}
+
+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.
+*/
+   nor->mtd.writesize = 16;
+
+   if (nor->mtd.size > SZ_128M) {
+   /*
+* For the multi-die package parts, the ready() hook is needed
+* to check all dies' status via read any register.
+*/
+   nor->ready = s25hx_t_mdp_ready;
+   } else {
+   int ret;
+   u8 cfr3v;
+
+   /*
+* Read CFR3V to check if uniform sector is selected. If not,
+* assign an erase hook that supports non-uniform erase,
+* assuming the part has factory default configuration,
+* 32 x 4KB sectors at bottom.
+*/
+   ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_CFR3V, 0,
+   );
+   if (ret)
+   return ret;
+
+   if (!(cfr3v & CFR3V_UNHYSA))
+   nor->mtd._erase = s25hx_t_erase_non_uniform;
+   }
+
+   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)
+{
+   int ret;
+   u32 addr;
+   u8 cfr3v;
+
+   /* erase size in case it is set to 4K from BFPT */
+   nor->erase_opcode = SPINOR_OP_SE_4B;
+   nor->mtd.erasesize = nor->info->sector_size;
+
+   /* Enter 4-byte addressing mode for Read Any Register */
+   ret = set_4byte(nor, nor->info, 1);
+   if (ret)
+   return ret;
+   nor->addr_width = 4;
+
+   /*
+* 

[PATCH v5 08/10] mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

Cypress chips support SPINOR_OP_EN4B(B7h)/SPINOR_OP_EX4B(E9h) to
enable/disable 4-byte addressing mode.

Signed-off-by: Takahiro Kuwano 
---
 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 46948ed41b..8d63681cb3 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -492,6 +492,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);
 
-- 
2.25.1



[PATCH v5 06/10] mtd: spi-nor-core: Read status by Read Any Register

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

The spansion_sr_ready() reads status register 1 by Read Any Register
commnad. This function is called from Flash specific hook with die address
and dummy cycles to support multi-die package parts from Spansion/Cypress.

Signed-off-by: Takahiro Kuwano 
---
Changes in v5:
  - New in v5, separated from another patch

 drivers/mtd/spi/spi-nor-core.c | 29 +
 include/linux/mtd/spi-nor.h|  1 +
 2 files changed, 30 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 821617bc0d..e5fc0e7965 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -522,6 +522,35 @@ static int set_4byte(struct spi_nor *nor, const struct 
flash_info *info,
}
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/*
+ * Read status register 1 by using Read Any Register command to support multi
+ * die package parts.
+ */
+static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy)
+{
+   u32 reg_addr = addr_base + SPINOR_REG_ADDR_STR1V;
+   u8 sr;
+   int ret;
+
+   ret = spansion_read_any_reg(nor, reg_addr, dummy, );
+   if (ret < 0)
+   return ret;
+
+   if (sr & (SR_E_ERR | SR_P_ERR)) {
+   if (sr & SR_E_ERR)
+   dev_dbg(nor->dev, "Erase Error occurred\n");
+   else
+   dev_dbg(nor->dev, "Programming Error occurred\n");
+
+   nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
+   return -EIO;
+   }
+
+   return !(sr & SR_WIP);
+}
+#endif
+
 static int spi_nor_sr_ready(struct spi_nor *nor)
 {
int sr = read_sr(nor);
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 2f2ad20e8e..25234177de 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -123,6 +123,7 @@
 #define SPINOR_OP_CLSR 0x30/* Clear status register 1 */
 #define SPINOR_OP_RDAR 0x65/* Read any register */
 #define SPINOR_OP_WRAR 0x71/* Write any register */
+#define SPINOR_REG_ADDR_STR1V  0x0080
 #define SPINOR_REG_ADDR_CFR1V  0x0082
 
 /* Used for Micron flashes only. */
-- 
2.25.1



[PATCH v5 07/10] mtd: spi-nor-core: Add non-uniform erase for Spansion/Cypress

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

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.

The spansion_erase_non_uniform() erases overlaid 4KB sectors,
non-overlaid portion of normal sector, and remaining normal sectors, by
selecting correct erase command and size based on the address to erase
and size of overlaid portion in parameters.

Signed-off-by: Takahiro Kuwano 
---
Changes in v5:
  - New in v5, introduce spansion_erase_non_uniform() as a replacement
for spansion_overlaid_erase() in v4

 drivers/mtd/spi/spi-nor-core.c | 72 ++
 1 file changed, 72 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index e5fc0e7965..46948ed41b 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -793,6 +793,78 @@ erase_err:
return ret;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/**
+ * spansion_erase_non_uniform() - erase non-uniform sectors for 
Spansion/Cypress
+ *chips
+ * @mtd:   pointer to a 'struct mtd_info'
+ * @instr: pointer to a 'struct erase_info'
+ * @ovlsz_top: size of overlaid portion at the top address
+ * @ovlsz_btm: size of overlaid portion at the bottom address
+ *
+ * Erase an address range on the nor chip that can contain 4KB sectors overlaid
+ * on top and/or bottom. The appropriate erase opcode and size are chosen by
+ * address to erase and size of overlaid portion.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spansion_erase_non_uniform(struct mtd_info *mtd,
+ struct erase_info *instr, u32 ovlsz_top,
+ u32 ovlsz_btm)
+{
+   struct spi_nor *nor = mtd_to_spi_nor(mtd);
+   struct spi_mem_op op =
+   SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1),
+  SPI_MEM_OP_ADDR(nor->addr_width, instr->addr, 1),
+  SPI_MEM_OP_NO_DUMMY,
+  SPI_MEM_OP_NO_DATA);
+   u32 len = instr->len;
+   u32 erasesize;
+   int ret;
+
+   while (len) {
+   /* 4KB sectors */
+   if (op.addr.val < ovlsz_btm ||
+   op.addr.val >= mtd->size - ovlsz_top) {
+   op.cmd.opcode = SPINOR_OP_BE_4K;
+   erasesize = SZ_4K;
+
+   /* Non-overlaid portion in the normal sector at the bottom */
+   } else if (op.addr.val == ovlsz_btm) {
+   op.cmd.opcode = nor->erase_opcode;
+   erasesize = mtd->erasesize - ovlsz_btm;
+
+   /* Non-overlaid portion in the normal sector at the top */
+   } else if (op.addr.val == mtd->size - mtd->erasesize) {
+   op.cmd.opcode = nor->erase_opcode;
+   erasesize = mtd->erasesize - ovlsz_top;
+
+   /* Normal sectors */
+   } else {
+   op.cmd.opcode = nor->erase_opcode;
+   erasesize = mtd->erasesize;
+   }
+
+   write_enable(nor);
+
+   ret = spi_mem_exec_op(nor->spi, );
+   if (ret)
+   break;
+
+   op.addr.val += erasesize;
+   len -= erasesize;
+
+   ret = spi_nor_wait_till_ready(nor);
+   if (ret)
+   break;
+   }
+
+   write_disable(nor);
+
+   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)
-- 
2.25.1



[PATCH v5 05/10] mtd: spi-nor-core: Add the ->ready() hook

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

For dual/quad die package devices from Spansion/Cypress, the device's
status needs to be checked by reading status registers in all dies, by
using Read Any Register command. To support this, a Flash specific hook
that can overwrite the legacy status check is needed.

The change in spi-nor.h depends on:
https://patchwork.ozlabs.org/project/uboot/patch/20210205041119.145784-4-sean...@gmail.com/
 

Signed-off-by: Takahiro Kuwano 
---
Changes in v5:
  - Move spansion_sr_ready() to different patch
  - Move original code in spi_nor_ready() to newly created
spi_nor_default_ready()

 drivers/mtd/spi/spi-nor-core.c | 10 +-
 include/linux/mtd/spi-nor.h|  2 ++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 87c9fce408..821617bc0d 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -566,7 +566,7 @@ static int spi_nor_fsr_ready(struct spi_nor *nor)
return fsr & FSR_READY;
 }
 
-static int spi_nor_ready(struct spi_nor *nor)
+static int spi_nor_default_ready(struct spi_nor *nor)
 {
int sr, fsr;
 
@@ -579,6 +579,14 @@ static int spi_nor_ready(struct spi_nor *nor)
return sr && fsr;
 }
 
+static int spi_nor_ready(struct spi_nor *nor)
+{
+   if (nor->ready)
+   return nor->ready(nor);
+
+   return spi_nor_default_ready(nor);
+}
+
 /*
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index d79f8b37ef..2f2ad20e8e 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -435,6 +435,7 @@ struct flash_info;
  * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
  * completely locked
  * @quad_enable:   [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @ready: [FLASH-SPECIFIC] check if the flash is ready
  * @priv:  the private data
  */
 struct spi_nor {
@@ -480,6 +481,7 @@ struct spi_nor {
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
+   int (*ready)(struct spi_nor *nor);
 
void *priv;
 /* Compatibility for spi_flash, remove once sf layer is merged with mtd */
-- 
2.25.1



[PATCH v5 04/10] mtd: spi-nor-core: Add support for volatile QE bit

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
Changes in v5:
  - Fix register address calculation, 'base | offset' -> 'base + offset' 

 drivers/mtd/spi/spi-nor-core.c | 53 ++
 include/linux/mtd/spi-nor.h|  1 +
 2 files changed, 54 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 2803536ed5..87c9fce408 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1576,6 +1576,59 @@ 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'
+ * @addr_base: base address of register (can be >0 in multi-die parts)
+ * @dummy: number of dummy cycles for register read
+ *
+ * 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, u32 addr_base,
+u8 dummy)
+{
+   u32 addr = addr_base + SPINOR_REG_ADDR_CFR1V;
+
+   u8 cr;
+   int ret;
+
+   /* Check current Quad Enable bit value. */
+   ret = spansion_read_any_reg(nor, addr, dummy, );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while reading configuration register\n");
+   return -EINVAL;
+   }
+
+   if (cr & CR_QUAD_EN_SPAN)
+   return 0;
+
+   cr |= CR_QUAD_EN_SPAN;
+
+   write_enable(nor);
+
+   ret = spansion_write_any_reg(nor, addr, cr);
+
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while writing configuration register\n");
+   return -EINVAL;
+   }
+
+   /* Read back and check it. */
+   ret = spansion_read_any_reg(nor, addr, dummy, );
+   if (ret || !(cr & 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/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 04bf59f6f9..d79f8b37ef 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -123,6 +123,7 @@
 #define SPINOR_OP_CLSR 0x30/* Clear status register 1 */
 #define SPINOR_OP_RDAR 0x65/* Read any register */
 #define SPINOR_OP_WRAR 0x71/* Write any register */
+#define SPINOR_REG_ADDR_CFR1V  0x0082
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_RD_EVCR  0x65/* Read EVCR register */
-- 
2.25.1



[PATCH v5 03/10] mtd: spi-nor-core: Add support for Read/Write Any Register

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

Some of Spansion/Cypress chips support Read/Write Any Register commands.
These commands are mainly used to write volatile registers and access to
the registers in second and subsequent die for multi-die package parts.

The Read Any Register instruction (65h) is followed by register address
and dummy cycles, then the selected register byte is returned.

The Write Any Register instruction (71h) is followed by register address
and register byte to write.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
Changes in v5:
  - Remove unused defines from spi-nor.h

 drivers/mtd/spi/spi-nor-core.c | 25 +
 include/linux/mtd/spi-nor.h|  2 ++
 2 files changed, 27 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 34c15f1561..2803536ed5 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -211,6 +211,31 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 
opcode, u8 *buf, int len)
return spi_nor_read_write_reg(nor, , buf);
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+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));
+
+   return spi_nor_read_write_reg(nor, , val);
+}
+
+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));
+
+   return spi_nor_read_write_reg(nor, , );
+}
+#endif
+
 static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
 u_char *buf)
 {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index d4f105df0f..04bf59f6f9 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_RDAR 0x65/* Read any register */
+#define SPINOR_OP_WRAR 0x71/* Write any register */
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_RD_EVCR  0x65/* Read EVCR register */
-- 
2.25.1



[PATCH v5 02/10] mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.

https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

The full version can be found in the following links (registration
required).
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-Semper-Flash-with-Quad-SPI/ta-p/260789?attachment-id=19522
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-2Gb-MCP-Semper-Flash-with-Quad-SPI/ta-p/260823?attachment-id=29503

Tested on Xilinx Zynq-7000 FPGA board.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
Changes in v5:
  - Remove 256Mb and 4Gb parts

 drivers/mtd/spi/spi-nor-ids.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 5bd5dd3003..052a0b62ee 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -217,6 +217,33 @@ 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 user-configurable
+* sector architecture. By default, the 512Mb and 1Gb, single-die
+* package parts are configured to non-uniform that 4KB sectors overlaid
+* on bottom address. To support this, an erase hook makes overlaid
+* sectors appear as uniform sectors. The 2Gb, dual-die package parts
+* are configured to uniform by default.
+*/
+   { 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("s25hl02gt",  0x342a1c, 0x0f0090, 256 * 1024, 1024,
+   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) },
+   { INFO6("s25hs02gt",  0x342b1c, 0x0f0090, 256 * 1024, 1024,
+   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 */
-- 
2.25.1



[PATCH v5 01/10] mtd: spi-nor: Add Cypress manufacturer ID

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

This patch adds Cypress manufacturer ID (34h) definition.

Signed-off-by: Takahiro Kuwano 
Reviewed-by: Pratyush Yadav 
---
 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 8e6744ac2e..d4f105df0f 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
-- 
2.25.1



[PATCH v5 00/10] mtd: spi-nor: Add support for Cypress s25hl-t/s25hs-t

2021-02-18 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.

The summary datasheets can be found in the following links.
https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

The full version can be found in the following links (registration
required).
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-Semper-Flash-with-Quad-SPI/ta-p/260789?attachment-id=19522
https://community.cypress.com/t5/Semper-Flash-Access-Program/Datasheet-2Gb-MCP-Semper-Flash-with-Quad-SPI/ta-p/260823?attachment-id=29503

Tested on Xilinx Zynq-7000 FPGA board.

Changes since v5:
  - Removed 256Mb and 4Gb parts support
  - Fixed register offset issue in spansion_quad_enable_volatile()
  - Added spi_nor_default_ready() and moved existing code into it
  - Separated spansion_sr_read() to new patch
  - Renamed spansion_overlaid_erase() to spansion_non_uniform_erase() and
changed the implementation to issue the proper erase command based on
the address
  - Added s25hx_t_erase_non_uniform()
  - Changed mtd.writesize and mtd.flags in s25hx_t_setup()
  - Fixed page size and erase size issues in s25hx_t_post_bfpt_fixup()

Changes since v4:
  - Added Read/Write Any Register support
  - Added the ->ready() hook to support multi-die package parts
  - Added S25HL02GT/S25HL04GT/S25HS02GT/S25HS04GT support
  
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.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/

Takahiro Kuwano (10):
  mtd: spi-nor: Add Cypress manufacturer ID
  mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t
  mtd: spi-nor-core: Add support for Read/Write Any Register
  mtd: spi-nor-core: Add support for volatile QE bit
  mtd: spi-nor-core: Add the ->ready() hook
  mtd: spi-nor-core: Read status by Read Any Register
  mtd: spi-nor-core: Add non-uniform erase for Spansion/Cypress
  mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte
  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 | 345 -
 drivers/mtd/spi/spi-nor-ids.c  |  27 +++
 drivers/mtd/spi/spi-nor-tiny.c |  90 +
 include/linux/mtd/spi-nor.h|  10 +
 4 files changed, 471 insertions(+), 1 deletion(-)
-- 
2.25.1


[PATCH v4 9/9] mtd: spi-nor-tiny: Add fixups for Cypress s25hl-t/s25hs-t

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

Fixes mode clocks for SPINOR_OP_READ_FAST_4B and volatile QE bit in tiny.
The volatile QE bit function, spansion_quad_enable_volatile() supports
dual/quad die package parts, by taking 'die_size' parameter that is used
to iterate register update for all dies in the device.

Signed-off-by: Takahiro Kuwano 
---
 drivers/mtd/spi/spi-nor-tiny.c | 89 ++
 1 file changed, 89 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index 5cc2b7d996..66680df5a9 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -555,6 +555,85 @@ 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'
+ * @die_size:  maximum number of bytes per die ('mtd.size' > 'die_size' in
+ *  multi die package parts).
+ * @dummy: number of dummy cycles for register read
+ *
+ * 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, u32 die_size,
+u8 dummy)
+{
+   struct spi_mem_op op =
+   SPI_MEM_OP(SPI_MEM_OP_CMD(0, 1),
+  SPI_MEM_OP_ADDR(4, 0, 1),
+  SPI_MEM_OP_DUMMY(0, 1),
+  SPI_MEM_OP_DATA_IN(1, NULL, 1));
+   u32 addr;
+   u8 cr;
+   int ret;
+
+   /* Use 4-byte address for RDAR/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;
+   }
+
+   for (addr = 0; addr < nor->mtd.size; addr += die_size) {
+   op.addr.val = addr + SPINOR_REG_ADDR_CFR1V;
+
+   /* Check current Quad Enable bit value. */
+   op.cmd.opcode = SPINOR_OP_RDAR;
+   op.dummy.nbytes = dummy / 8;
+   op.data.dir = SPI_MEM_DATA_IN;
+   ret = spi_nor_read_write_reg(nor, , );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while reading configuration register\n");
+   return -EINVAL;
+   }
+
+   if (cr & CR_QUAD_EN_SPAN)
+   return 0;
+
+   /* Write new value. */
+   cr |= CR_QUAD_EN_SPAN;
+   op.cmd.opcode = SPINOR_OP_WRAR;
+   op.dummy.nbytes = 0;
+   op.data.dir = SPI_MEM_DATA_OUT;
+   write_enable(nor);
+   ret = spi_nor_read_write_reg(nor, , );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while writing configuration register\n");
+   return -EINVAL;
+   }
+
+   /* Read back and check it. */
+   op.cmd.opcode = SPINOR_OP_RDAR;
+   op.dummy.nbytes = dummy / 8;
+   op.data.dir = SPI_MEM_DATA_IN;
+   ret = spi_nor_read_write_reg(nor, , );
+   if (ret || !(cr & 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,
@@ -583,6 +662,11 @@ static int spi_nor_init_params(struct spi_nor *nor,
spi_nor_set_read_settings(>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) {
@@ -659,6 +743,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, SZ_128M, 0);
+   break;
 #endif
case SNOR_MFR_ST:
case SNOR_MFR_MICRON:
-- 
2.25.1



[PATCH v4 8/9] mtd: spi-nor-core: Add fixups for Cypress s25hl-t/s25hs-t

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

Add nor->setup() and fixup hooks to overwrite:
  - volatile QE bit
  - the ->ready() hook for dual/quad die package parts
  - overlaid erase
  - spi_nor_flash_parameter
  - mtd_info

Signed-off-by: Takahiro Kuwano 
---
 drivers/mtd/spi/spi-nor-core.c | 108 +
 1 file changed, 108 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index ef49328a28..3d8cb9c333 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2648,8 +2648,116 @@ static int spi_nor_init(struct spi_nor *nor)
return 0;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+static int s25hx_t_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);
+   if (ret != 1)
+   return ret;
+   }
+
+   return 1;
+}
+
+static int s25hx_t_quad_enable(struct spi_nor *nor)
+{
+   u32 addr;
+   int ret;
+
+   for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) {
+   ret = spansion_quad_enable_volatile(nor, addr, 0);
+   if (ret)
+   return ret;
+   }
+
+   return 0;
+}
+
+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;
+
+   /* For 2Gb (dual die) and 4Gb (quad die) parts */
+   if (nor->mtd.size > SZ_128M)
+   nor->ready = s25hx_t_mdp_ready;
+
+   /* 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 = s25hx_t_quad_enable;
+}
+
+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 = _t_fixups;
+   break;
+
+   default:
+   break;
+   }
+   }
+#endif
 }
 
 int spi_nor_scan(struct spi_nor *nor)
-- 
2.25.1



[PATCH v4 7/9] mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

Cypress chips support SPINOR_OP_EN4B(B7h)/SPINOR_OP_EX4B(E9h) to
enable/disable 4-byte addressing mode.

Signed-off-by: Takahiro Kuwano 
---
 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 70da0081b6..ef49328a28 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -492,6 +492,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);
 
-- 
2.25.1



[PATCH v4 6/9] mtd: spi-nor-core: Add overlaid sector erase feature

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
 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 1c0ba5abf9..70da0081b6 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -788,6 +788,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, _4k);
+   }
+   if (!ret && instr->addr + instr->len == mtd->size) {
+   instr_4k.addr = mtd->size - instr_4k.len;
+   ret = spi_nor_erase(mtd, _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)
-- 
2.25.1



[PATCH v4 5/9] mtd: spi-nor-core: Add the ->ready() hook

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

For dual/quad die package devices from Spansion/Cypress, the device's
status needs to be checked by reading status registers in all dies, by
using Read Any Register command. To support this, a Flash specific hook
that can overwrite the legacy status check is needed.

The spansion_sr_ready() reads status register 1 by Read Any Register
commnad. This function is called from Flash specific hook with die address
and dummy cycles.

Signed-off-by: Takahiro Kuwano 
---
 drivers/mtd/spi/spi-nor-core.c | 32 
 include/linux/mtd/spi-nor.h|  4 +++-
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 624e730524..1c0ba5abf9 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -522,6 +522,35 @@ static int set_4byte(struct spi_nor *nor, const struct 
flash_info *info,
}
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/*
+ * Read status register 1 by using Read Any Register command to support multi
+ * die package parts.
+ */
+static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy)
+{
+   u32 reg_addr = addr_base + SPINOR_REG_ADDR_STR1V;
+   u8 sr;
+   int ret;
+
+   ret = spansion_read_any_reg(nor, reg_addr, dummy, );
+   if (ret < 0)
+   return ret;
+
+   if (sr & (SR_E_ERR | SR_P_ERR)) {
+   if (sr & SR_E_ERR)
+   dev_dbg(nor->dev, "Erase Error occurred\n");
+   else
+   dev_dbg(nor->dev, "Programming Error occurred\n");
+
+   nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
+   return -EIO;
+   }
+
+   return !(sr & SR_WIP);
+}
+#endif
+
 static int spi_nor_sr_ready(struct spi_nor *nor)
 {
int sr = read_sr(nor);
@@ -570,6 +599,9 @@ static int spi_nor_ready(struct spi_nor *nor)
 {
int sr, fsr;
 
+   if (nor->ready)
+   return nor->ready(nor);
+
sr = spi_nor_sr_ready(nor);
if (sr < 0)
return sr;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index e31073eb24..25234177de 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -434,8 +434,9 @@ struct flash_info;
  * @flash_lock:[FLASH-SPECIFIC] lock a region of the SPI NOR
  * @flash_unlock:  [FLASH-SPECIFIC] unlock a region of the SPI NOR
  * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
- * @quad_enable:   [FLASH-SPECIFIC] enables SPI NOR quad mode
  * completely locked
+ * @quad_enable:   [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @ready: [FLASH-SPECIFIC] check if the flash is ready
  * @priv:  the private data
  */
 struct spi_nor {
@@ -481,6 +482,7 @@ struct spi_nor {
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
+   int (*ready)(struct spi_nor *nor);
 
void *priv;
 /* Compatibility for spi_flash, remove once sf layer is merged with mtd */
-- 
2.25.1



[PATCH v4 4/9] mtd: spi-nor-core: Add support for volatile QE bit

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
 drivers/mtd/spi/spi-nor-core.c | 53 ++
 1 file changed, 53 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 2803536ed5..624e730524 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1576,6 +1576,59 @@ 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'
+ * @addr_base: base address of register (can be >0 in multi-die parts)
+ * @dummy: number of dummy cycles for register read
+ *
+ * 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, u32 addr_base,
+u8 dummy)
+{
+   u32 addr = addr_base | SPINOR_REG_ADDR_CFR1V;
+
+   u8 cr;
+   int ret;
+
+   /* Check current Quad Enable bit value. */
+   ret = spansion_read_any_reg(nor, addr, dummy, );
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while reading configuration register\n");
+   return -EINVAL;
+   }
+
+   if (cr & CR_QUAD_EN_SPAN)
+   return 0;
+
+   cr |= CR_QUAD_EN_SPAN;
+
+   write_enable(nor);
+
+   ret = spansion_write_any_reg(nor, addr, cr);
+
+   if (ret < 0) {
+   dev_dbg(nor->dev,
+   "error while writing configuration register\n");
+   return -EINVAL;
+   }
+
+   /* Read back and check it. */
+   ret = spansion_read_any_reg(nor, addr, dummy, );
+   if (ret || !(cr & 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.
-- 
2.25.1



[PATCH v4 3/9] mtd: spi-nor-core: Add support for Read/Write Any Register

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

Some of Spansion/Cypress chips support Read/Write Any Register commands.
These commands are mainly used to write volatile registers and access to
the registers in second and subsequent die for multi-die package parts.

The Read Any Register instruction (65h) is followed by register address
and dummy cycles, then the selected register byte is returned.

The Write Any Register instruction (71h) is followed by register address
and register byte to write.

Signed-off-by: Takahiro Kuwano 
---
 drivers/mtd/spi/spi-nor-core.c | 25 +
 include/linux/mtd/spi-nor.h|  4 
 2 files changed, 29 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 34c15f1561..2803536ed5 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -211,6 +211,31 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 
opcode, u8 *buf, int len)
return spi_nor_read_write_reg(nor, , buf);
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+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));
+
+   return spi_nor_read_write_reg(nor, , val);
+}
+
+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));
+
+   return spi_nor_read_write_reg(nor, , );
+}
+#endif
+
 static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
 u_char *buf)
 {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 89e7a4fdcd..e31073eb24 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -121,6 +121,10 @@
 #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_RDAR 0x65/* Read any register */
+#define SPINOR_OP_WRAR 0x71/* Write any register */
+#define SPINOR_REG_ADDR_STR1V  0x0080
+#define SPINOR_REG_ADDR_CFR1V  0x0082
 
 /* Used for Micron flashes only. */
 #define SPINOR_OP_RD_EVCR  0x65/* Read EVCR register */
-- 
2.25.1



[PATCH v4 2/9] mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.
The datasheets can be found in the following links.

https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

Tested 512Mb/1Gb/2Gb parts on Xilinx Zynq-7000 FPGA board.

Signed-off-by: Takahiro Kuwano 
---
 drivers/mtd/spi/spi-nor-ids.c | 36 +++
 1 file changed, 36 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 5bd5dd3003..b78d13e980 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -217,6 +217,42 @@ 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("s25hl02gt",  0x342a1c, 0x0f0090, 256 * 1024, 1024,
+   SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES |
+   USE_CLSR) },
+   { INFO6("s25hl04gt",  0x342a1d, 0x0f0090, 256 * 1024, 2048,
+   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) },
+   { INFO6("s25hs02gt",  0x342b1c, 0x0f0090, 256 * 1024, 1024,
+   SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES |
+   USE_CLSR) },
+   { INFO6("s25hs04gt",  0x342b1d, 0x0f0090, 256 * 1024, 2048,
+   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 */
-- 
2.25.1



[PATCH v4 1/9] mtd: spi-nor: Add Cypress manufacturer ID

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

This patch adds Cypress manufacturer ID (34h) definition.

Signed-off-by: Takahiro Kuwano 
---
 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
-- 
2.25.1



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

2021-01-27 Thread tkuw584924
From: Takahiro Kuwano 

The S25HL-T/S25HS-T family is the Cypress Semper Flash with Quad SPI.
The datasheets can be found in the following links.

https://www.cypress.com/file/424146/download (256Mb/512Mb/1Gb, single die)
https://www.cypress.com/file/499246/download (2Gb/4Gb, dual/quad die)

Tested on Xilinx Zynq-7000 FPGA board.

Takahiro Kuwano (9):
  mtd: spi-nor: Add Cypress manufacturer ID
  mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t
  mtd: spi-nor-core: Add support for Read/Write Any Register
  mtd: spi-nor-core: Add support for volatile QE bit
  mtd: spi-nor-core: Add the ->ready() hook
  mtd: spi-nor-core: Add overlaid sector erase feature
  mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte
  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 | 267 +
 drivers/mtd/spi/spi-nor-ids.c  |  36 +
 drivers/mtd/spi/spi-nor-tiny.c |  89 +++
 include/linux/mtd/spi-nor.h|   9 +-
 4 files changed, 400 insertions(+), 1 deletion(-)

---
Changes since v4:
  - Added Read/Write Any Register support
  - Added the ->ready() hook to support multi-die package parts
  - Added S25HL02GT/S25HL04GT/S25HS02GT/S25HS04GT support
  
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.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/

--
2.25.1



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

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

Fixes mode clocks for SPINOR_OP_READ_FAST_4B and volatile QE bit in tiny.

Signed-off-by: Takahiro Kuwano 
---
 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(>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:
-- 
2.25.1



[PATCH v3 4/7] mtd: spi-nor-core: Add Cypress manufacturer ID in set_4byte

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

Cypress chips support SPINOR_OP_EN4B(B7h)/SPINOR_OP_EX4B(E9h) to
enable/disable 4-byte addressing mode.

Signed-off-by: Takahiro Kuwano 
---
 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);
 
-- 
2.25.1



[PATCH v3 2/7] mtd: spi-nor-ids: Add Cypress s25hl-t/s25hs-t

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
 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 */
-- 
2.25.1



[PATCH v3 3/7] mtd: spi-nor: Add support for volatile QE bit

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
 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, , );
+
+   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, , );
+
+   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;
+   }
+
+  

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

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

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.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/

-- 
2.25.1



[PATCH v3 6/7] mtd: spi-nor-core: Add fixups for Cypress s25hl-t/s25hs-t

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

Add nor->setup() and fixup hooks for volatile QE bit, overlaid erase,
spi_nor_flash_parameter and mtd_info.

Signed-off-by: Takahiro Kuwano 
---

Depends on the following patches:
 
https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-7-p.ya...@ti.com/
 
https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/
 
https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/


 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 = _t_fixups;
+   break;
+
+   default:
+   break;
+   }
+   }
+#endif
 }
 
 int spi_nor_scan(struct spi_nor *nor)
-- 
2.25.1



[PATCH v3 5/7] mtd: spi-nor-core: Add overlaid sector erase feature

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

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 
---
 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, _4k);
+   }
+   if (!ret && instr->addr + instr->len == mtd->size) {
+   instr_4k.addr = mtd->size - instr_4k.len;
+   ret = spi_nor_erase(mtd, _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)
-- 
2.25.1



[PATCH v3 1/7] mtd: spi-nor: Add Cypress manufacturer ID

2020-11-04 Thread tkuw584924
From: Takahiro Kuwano 

This patch adds Cypress manufacturer ID (34h) definition.

Signed-off-by: Takahiro Kuwano 
---
 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
-- 
2.25.1



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

2020-10-01 Thread tkuw584924
From: Takahiro Kuwano 

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

This device family can be configured to non-uniform sector layout, while
U-Boot does not support it. To handle this, an erase hook emulates uniform
sector layout. To enable quad mode, using volatile register is recommended
for safety. And some other fixups for spi_nor_flash_parameter and mtd_info
are added.

Tested on Xilinx Zynq-7000 FPGA board.

Signed-off-by: Takahiro Kuwano 
---

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.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-8-p.ya...@ti.com/

https://patchwork.ozlabs.org/project/uboot/patch/20200904153500.3569-9-p.ya...@ti.com/
  
 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(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 5264d24fd0..98811ce8cc 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -466,6 +466,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);
 
@@ -730,6 +731,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, _4k);
+   }
+   if (!ret && instr->addr + instr->len == mtd->size) {
+   instr_4k.addr = mtd->size - instr_4k.len;
+   ret = spi_nor_erase(mtd, _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)
@@ -1550,6 +1599,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;
+
+   

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

2020-09-24 Thread tkuw584924
From: Takahiro Kuwano 

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

This device family can be configured to non-uniform sector layout, while
U-Boot does not support it. To handle this, an erase hook emulates uniform
sector layout. To enable quad mode, using volatile register is recommended
for safety. And some other fixups for spi_nor_flash_parameter and mtd_info
are added.

Tested on Xilinx Zynq-7000 FPGA board.

Signed-off-by: Takahiro Kuwano 
---
 drivers/mtd/spi/spi-nor-core.c | 137 +
 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, 237 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 0113e70037..ddb1cb6bcc 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -329,6 +329,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);
 
@@ -593,6 +594,54 @@ erase_err:
return ret;
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/*
+ * Erase for Spansioin/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 < erasesize) {
+   instr_4k.addr = 0;
+   ret = spi_nor_erase(mtd, _4k);
+   }
+   if (!ret && instr->addr + instr->len >= mtd->size - erasesize) {
+   instr_4k.addr = mtd->size - instr_4k.len;
+   ret = spi_nor_erase(mtd, _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)
@@ -1413,6 +1462,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, , );
+
+   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)
 /**
  

<    1   2