diff mbox series

[v3,v3,3/3] mtd: spi-nor: add locking support for is25xxxxx device

Message ID 1557244775-14206-3-git-send-email-sagar.kadam@sifive.com
State Changes Requested
Delegated to: Ambarus Tudor
Headers show
Series [v3,v3,1/3] mtd: spi-nor: add support for is25wp256 | expand

Commit Message

Sagar Shrikant Kadam May 7, 2019, 3:59 p.m. UTC
Implement a basic locking scheme for ISSI devices similar to that of
stm_lock mechanism. The is25xxxxx  devices have 4 bits for selecting
the range of blocks to be locked/protected from erase/write.

The current implementation enables block protection as per the table
defined into datasheet for is25wp256d device.

Signed-off-by: Sagar Shrikant Kadam <sagar.kadam@sifive.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 51 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
diff mbox series

Patch

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 3942b26..5986260 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1459,6 +1459,56 @@  static int macronix_quad_enable(struct spi_nor *nor)
 
 	return 0;
 }
+/**
+ * issi_lock() - set BP[0123] write-protection.
+ * @nor: pointer to a 'struct spi_nor'.
+ * @ofs: offset from which to lock memory.
+ * @len: number of bytes to unlock.
+ *
+ * Lock a region of the flash.Implementation is based on stm_lock
+ * Supports the block protection bits BP{0,1,2,3} in the status register
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int issi_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+{
+	int status_old, status_new, blk_prot;
+	u8 mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
+	u8 shift = ffs(mask) - 1;
+	u8 pow;
+	loff_t num_blks;
+
+	status_old = read_sr(nor);
+
+	/* if status reg is Write protected don't update bit protection */
+	if (status_old & SR_SRWD) {
+		dev_err(nor->dev,
+			"Status register is Write Protected, can't lock bit
+			protection bits...\n");
+		return -EINVAL;
+	}
+	num_blks = len / nor->info->sector_size;
+
+	pow = order_base_2(num_blks);
+
+	blk_prot = mask & (((pow+1) & 0xf)<<shift);
+
+	/*
+	 * Return if older protected blocks include the new requested block's
+	 */
+	if (((status_old >> shift) & 0x0f) > blk_prot) {
+		dev_info(nor->dev, "newly requested blocks are
+				already protected ");
+		return 0;
+	}
+
+	status_new = status_old | blk_prot;
+
+	if (status_old == status_new)
+		return 0;
+
+	return write_sr_and_check(nor, status_new, mask);
+}
 
 /**
  * issi_unlock() - clear BP[0123] write-protection.
@@ -4124,6 +4174,7 @@  int spi_nor_scan(struct spi_nor *nor, const char *name,
 	/* NOR protection support for ISSI chips */
 	if (JEDEC_MFR(info) == SNOR_MFR_ISSI ||
 	    info->flags & SPI_NOR_HAS_LOCK) {
+		nor->flash_lock = issi_lock;
 		nor->flash_unlock = issi_unlock;
 
 	}