[PATCH v1 5/7] sf protect (un)lock for SST26*: test BPR values

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


after writing new block protection bits, read back the block protection
bit register and test whether the desired settings were accepted. fail
with error message otherwise.

this adjusts the behavior of "sf protect (un)lock" for SST26* chips to
be similar to the (un)locking behavior of Micron-compatible chips, where
the statur register is read back and checked after writing it with the
new block protection bit setting.

comparing the desired and current values fails if hardware write
protection is enabled (SRWD (Micron) or WPEN (SST26*) bit set), and the
WP# pin is not asserted, as the respective registers are write-protected
in that case.

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

 drivers/mtd/spi/spi-nor-core.c | 55 +++++++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 10c01cf20e..b3873aaf6e 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -998,6 +998,47 @@ static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl)
 	return false;
 }
 
+static int sst26_read_bpr(struct spi_nor *nor, u8 *buff, u32 *len)
+{
+	struct mtd_info *mtd = &nor->mtd;
+	u32 bpr_size;
+	int ret;
+
+	bpr_size = 2 + (mtd->size / SZ_64K / 8);
+
+	if (*len < bpr_size) {
+		dev_err(nor->dev, "block-protection register buffer too small\n");
+		return -EINVAL;
+	}
+
+	ret = nor->read_reg(nor, SPINOR_OP_READ_BPR, buff, bpr_size);
+	if (ret < 0) {
+		dev_err(nor->dev, "failed to read block-protection register\n");
+		return ret;
+	}
+
+	*len = bpr_size;
+	return 0;
+}
+
+static int sst26_check_bpr(struct spi_nor *nor, u8 *expected_buf, u32 expected_len)
+{
+	u8 actual_buf[SST26_MAX_BPR_REG_LEN] = {};
+	u32 actual_len = SST26_MAX_BPR_REG_LEN;
+	int ret;
+
+	ret = sst26_read_bpr(nor, actual_buf, &actual_len);
+	if (ret < 0)
+		return ret;
+
+	if (expected_len != actual_len || memcmp(expected_buf, actual_buf, actual_len)) {
+		dev_err(nor->dev, "device did not accept new block protection bits\n");
+		return -EACCES;
+	}
+
+	return 0;
+}
+
 static int sst26_hardware_write_protection(struct spi_nor *nor, bool lock)
 {
 	int ret;
@@ -1034,7 +1075,7 @@ static int sst26_hardware_write_protection(struct spi_nor *nor, bool lock)
 static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lock_ctl ctl)
 {
 	struct mtd_info *mtd = &nor->mtd;
-	u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size;
+	u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size = SST26_MAX_BPR_REG_LEN;
 	bool lower_64k = false, upper_64k = false;
 	u8 bpr_buff[SST26_MAX_BPR_REG_LEN] = {};
 	int ret;
@@ -1057,13 +1098,9 @@ static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lo
 	    mtd->size != SZ_8M)
 		return -EINVAL;
 
-	bpr_size = 2 + (mtd->size / SZ_64K / 8);
-
-	ret = nor->read_reg(nor, SPINOR_OP_READ_BPR, bpr_buff, bpr_size);
-	if (ret < 0) {
-		dev_err(nor->dev, "fail to read block-protection register\n");
+	ret = sst26_read_bpr(nor, bpr_buff, &bpr_size);
+	if (ret < 0)
 		return ret;
-	}
 
 	rptr_64k = min_t(u32, ofs + len, mtd->size - SST26_BOUND_REG_SIZE);
 	lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE);
@@ -1134,6 +1171,10 @@ static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lo
 		return ret;
 	}
 
+	ret = sst26_check_bpr(nor, bpr_buff, bpr_size);
+	if (ret < 0)
+		return ret;
+
 	// enable hardware write protection iff any protection bit is set
 	for (i = 0; i < bpr_size; ++i)
 		if (bpr_buff[i] != 0)
-- 
2.29.2



More information about the U-Boot mailing list