[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20190731090315.26798-6-tudor.ambarus@microchip.com>
Date: Wed, 31 Jul 2019 09:03:35 +0000
From: <Tudor.Ambarus@...rochip.com>
To: <boris.brezillon@...labora.com>, <marek.vasut@...il.com>,
<vigneshr@...com>
CC: <dwmw2@...radead.org>, <computersforpeace@...il.com>,
<miquel.raynal@...tlin.com>, <richard@....at>,
<linux-mtd@...ts.infradead.org>, <linux-kernel@...r.kernel.org>,
<boris.brezillon@...tlin.com>, <Tudor.Ambarus@...rochip.com>
Subject: [PATCH 5/7] mtd: spi-nor: Create a ->set_4byte() method
From: Boris Brezillon <boris.brezillon@...tlin.com>
The procedure used to enable 4 byte addressing mode depends on the NOR
device, so let's provide a hook so that manufacturer specific handling
can be implemented in a sane way.
set_4byte methods can be amended when parsing BFPT.
Signed-off-by: Boris Brezillon <boris.brezillon@...tlin.com>
Signed-off-by: Tudor Ambarus <tudor.ambarus@...rochip.com>
---
drivers/mtd/spi-nor/spi-nor.c | 119 ++++++++++++++++++++++--------------------
include/linux/mtd/spi-nor.h | 3 ++
2 files changed, 64 insertions(+), 58 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index b2e72668e7ab..e35aae88d38b 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -758,6 +758,21 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
}
}
+static int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
+{
+ if (nor->spimem) {
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 1),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+
+ return spi_nor_data_op(nor, &op, &ear, 1);
+ }
+
+ return nor->write_reg(nor, SPINOR_OP_WREAR, &ear, 1);
+}
+
static int macronix_set_4byte(struct spi_nor *nor, bool enable)
{
if (nor->spimem) {
@@ -777,6 +792,39 @@ static int macronix_set_4byte(struct spi_nor *nor, bool enable)
NULL, 0);
}
+static int st_micron_set_4byte(struct spi_nor *nor, bool enable)
+{
+ int ret;
+
+ write_enable(nor);
+ ret = macronix_set_4byte(nor, enable);
+ write_disable(nor);
+
+ return ret;
+}
+
+static int winbond_set_4byte(struct spi_nor *nor, bool enable)
+{
+ int ret;
+
+ ret = macronix_set_4byte(nor, enable);
+ if (ret || enable)
+ return ret;
+
+ /*
+ * On Winbond W25Q256FV, leaving 4byte mode causes the Extended Address
+ * Register to be set to 1, so all 3-byte-address reads come from the
+ * second 16M.
+ * We must clear the register to enable normal behavior.
+ */
+ write_enable(nor);
+ nor->cmd_buf[0] = 0;
+ ret = spi_nor_write_ear(nor, nor->cmd_buf[0]);
+ write_disable(nor);
+
+ return ret;
+}
+
static int spansion_set_4byte(struct spi_nor *nor, bool enable)
{
u8 quad_en = enable << 7;
@@ -794,62 +842,6 @@ static int spansion_set_4byte(struct spi_nor *nor, bool enable)
return nor->write_reg(nor, SPINOR_OP_BRWR, &quad_en, 1);
}
-static int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
-{
- if (nor->spimem) {
- struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 1),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(0, NULL, 1));
-
- return spi_nor_data_op(nor, &op, &ear, 1);
- }
-
- return nor->write_reg(nor, SPINOR_OP_WREAR, &ear, 1);
-}
-
-/* Enable/disable 4-byte addressing mode. */
-static int set_4byte(struct spi_nor *nor, bool enable)
-{
- int status;
- bool need_wren = false;
-
- switch (JEDEC_MFR(nor->info)) {
- case SNOR_MFR_ST:
- case SNOR_MFR_MICRON:
- /* Some Micron need WREN command; all will accept it */
- need_wren = true;
- /* fall through */
- case SNOR_MFR_MACRONIX:
- case SNOR_MFR_WINBOND:
- if (need_wren)
- write_enable(nor);
-
- status = macronix_set_4byte(nor, enable);
- if (need_wren)
- write_disable(nor);
-
- if (!status && !enable &&
- JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) {
- /*
- * On Winbond W25Q256FV, leaving 4byte mode causes
- * the Extended Address Register to be set to 1, so all
- * 3-byte-address reads come from the second 16M.
- * We must clear the register to enable normal behavior.
- */
- write_enable(nor);
- spi_nor_write_ear(nor, 0);
- write_disable(nor);
- }
-
- return status;
- default:
- /* Spansion style */
- return spansion_set_4byte(nor, enable);
- }
-}
-
static int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr)
{
if (nor->spimem) {
@@ -4287,11 +4279,18 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
static void macronix_set_default_init(struct spi_nor *nor)
{
nor->quad_enable = macronix_quad_enable;
+ nor->set_4byte = macronix_set_4byte;
}
static void st_micron_set_default_init(struct spi_nor *nor)
{
nor->quad_enable = NULL;
+ nor->set_4byte = st_micron_set_4byte;
+}
+
+static void winbond_set_default_init(struct spi_nor *nor)
+{
+ nor->set_4byte = winbond_set_4byte;
}
static void spi_nor_mfr_init_params(struct spi_nor *nor,
@@ -4307,6 +4306,9 @@ static void spi_nor_mfr_init_params(struct spi_nor *nor,
st_micron_set_default_init(nor);
break;
+ case SNOR_MFR_WINBOND:
+ winbond_set_default_init(nor);
+ break;
default:
break;
}
@@ -4685,7 +4687,7 @@ static int spi_nor_init(struct spi_nor *nor)
*/
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
"enabling reset hack; may not recover from unexpected reboots\n");
- set_4byte(nor, true);
+ nor->set_4byte(nor, true);
}
return 0;
@@ -4709,7 +4711,7 @@ void spi_nor_restore(struct spi_nor *nor)
/* restore the addressing mode */
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
- set_4byte(nor, false);
+ nor->set_4byte(nor, false);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
@@ -4801,6 +4803,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
/* Kept only for backward compatibility purpose. */
nor->quad_enable = spansion_quad_enable;
+ nor->set_4byte = spansion_set_4byte;
/* Init flash parameters based on flash_info struct and SFDP */
spi_nor_init_params(nor, ¶ms);
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4521a38452d6..a434ab7a53e6 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -378,6 +378,8 @@ struct flash_info;
* @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
+ * @set_4byte: [FLASH-SPECIFIC] puts the SPI NOR in 4 byte addressing
+ * mode
* @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
* the SPI NOR Status Register.
* completely locked
@@ -420,6 +422,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 (*set_4byte)(struct spi_nor *nor, bool enable);
int (*clear_sr_bp)(struct spi_nor *nor);
void *priv;
--
2.9.5
Powered by blists - more mailing lists