[PATCH v1 4/7] write WPEN bit for SST26* devices when locking

Bernhard Kirchen schlimmchen at gmail.com
Thu Jan 28 17:18:44 CET 2021


"sf protect lock" did only protect against accidental writes by
software. it did not lock down the config or block-protection registers
if the WP# pin was deasserted. hardware write protection was never
enabled for these devices.

this change implements setting the WPEN bit and clearing the IOC bit in
SST26* devices' config register if any block is protected by "sf protect
lock" command, thus enabling hardware write protection. this behavior is
similar to the "sf protect lock" implementation for Micron (and
compatible) chips.

Signed-off-by: Bernhard Kirchen <bernhard.kirchen at mbconnectline.com>
---

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

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 050aeac3fa..10c01cf20e 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -185,7 +185,9 @@ static int read_fsr(struct spi_nor *nor)
  * location. Return the configuration register value.
  * Returns negative if error occurred.
  */
-#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+#if defined(CONFIG_SPI_FLASH_SPANSION) || \
+	defined(CONFIG_SPI_FLASH_WINBOND) || \
+	defined(CONFIG_SPI_FLASH_SST)
 static int read_cr(struct spi_nor *nor)
 {
 	int ret;
@@ -972,6 +974,8 @@ read_err:
 #define SST26_MAX_BPR_REG_LEN		(18 + 1)
 #define SST26_BOUND_REG_SIZE		((32 + SST26_BPR_8K_NUM * 8) * SZ_1K)
 
+static int write_cr(struct spi_nor *nor, u8 value);
+
 enum lock_ctl {
 	SST26_CTL_LOCK,
 	SST26_CTL_UNLOCK,
@@ -994,6 +998,35 @@ static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
 	return false;
 }
 
+static int sst26_hardware_write_protection(struct spi_nor *nor, bool lock)
+{
+	int ret;
+	u8 cr_val;
+
+	cr_val = read_cr(nor);
+	if (cr_val < 0) {
+		dev_err(nor->dev, "fail to read config register value\n");
+		return cr_val;
+	}
+
+	cr_val &= ~CR_WPEN;
+
+	if (lock) {
+		// disallow further writes if WP# pin is not asserted.
+		cr_val |= CR_WPEN;
+		// force quad SPI disabled as otherwise WP# pin works as data line.
+		cr_val &= ~CR_QUAD_EN_SPAN;
+	}
+
+	ret = write_cr(nor, cr_val);
+	if (ret < 0) {
+		dev_err(nor->dev, "fail to configure WP# pin (hardware write protection)\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 /*
  * Lock, unlock or check lock status of the flash region of the flash (depending
  * on the lock_ctl value)
@@ -1101,6 +1134,14 @@ static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lo
 		return ret;
 	}
 
+	// enable hardware write protection iff any protection bit is set
+	for (i = 0; i < bpr_size; ++i)
+		if (bpr_buff[i] != 0)
+			break;
+	ret = sst26_hardware_write_protection(nor, i < bpr_size);
+	if (ret < 0)
+		return ret;
+
 	// ignore return value. even if write disable failed, the actual task
 	// (write block protecton register) was completed successfully.
 	write_disable(nor);
@@ -1339,7 +1380,9 @@ static int macronix_quad_enable(struct spi_nor *nor)
 }
 #endif
 
-#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
+#if defined(CONFIG_SPI_FLASH_SPANSION) || \
+	defined(CONFIG_SPI_FLASH_WINBOND) || \
+	defined(CONFIG_SPI_FLASH_SST)
 /*
  * Write status Register and configuration register with 2 bytes
  * The first byte will be written to the status register, while the
@@ -1369,6 +1412,23 @@ static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr)
 	return 0;
 }
 
+static int write_cr(struct spi_nor *nor, u8 value)
+{
+	int ret;
+	u8 sr_cr[2];
+
+	ret = read_sr(nor);
+	if (ret < 0)
+		return ret;
+
+	sr_cr[0] = ret;
+	sr_cr[1] = value;
+
+	return write_sr_cr(nor, sr_cr);
+}
+#endif
+
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
 /**
  * spansion_read_cr_quad_enable() - set QE bit in Configuration Register.
  * @nor:	pointer to a 'struct spi_nor'
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4a8e19ee4f..ee5a59cf0a 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -151,6 +151,7 @@
 
 /* Configuration Register bits. */
 #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */
+#define CR_WPEN			BIT(7)	/* SST26* Write-Protection Pin (WP#) Enable */
 
 /* Status Register 2 bits. */
 #define SR2_QUAD_EN_BIT7	BIT(7)
-- 
2.29.2



More information about the U-Boot mailing list