[coreboot-gerrit] Change in coreboot[master]: [WIP]drivers/spi: Winbond specific writeprotection enable

Patrick Rudolph (Code Review) gerrit at coreboot.org
Mon Mar 12 15:07:31 CET 2018


Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/25105


Change subject: [WIP]drivers/spi: Winbond specific writeprotection enable
......................................................................

[WIP]drivers/spi: Winbond specific writeprotection enable

Extend the SPI interface to enable write protection.

Change-Id: Ie3765b013855538eca37bc7800d3f9d5d09b8402
Signed-off-by: Patrick Rudolph <patrick.rudolph at 9elements.com>
---
M src/drivers/spi/spi_flash.c
M src/drivers/spi/winbond.c
M src/include/spi_flash.h
3 files changed, 196 insertions(+), 3 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/05/25105/1

diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c
index 9bad9f3..769ef48 100644
--- a/src/drivers/spi/spi_flash.c
+++ b/src/drivers/spi/spi_flash.c
@@ -452,6 +452,28 @@
 	return flash->ops->get_write_protection(flash, region);
 }
 
+int spi_flash_set_write_protected(const struct spi_flash *flash,
+				  const struct region *region)
+{
+	struct region flash_region = { 0 };
+
+	if (!flash)
+		return -1;
+
+	flash_region.size = flash->size;
+
+	if (!region_is_subregion(&flash_region, region))
+		return -1;
+
+	if (flash->ops->set_write_protection) {
+		printk(BIOS_WARNING, "SPI: Setting write-protection is not "
+		       "implemented for this vendor.\n");
+		return 0;
+	}
+
+	return flash->ops->set_write_protection(flash, region);
+}
+
 static uint32_t volatile_group_count CAR_GLOBAL;
 
 int spi_flash_volatile_group_begin(const struct spi_flash *flash)
diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c
index 6c1ce0d..2992dc3 100644
--- a/src/drivers/spi/winbond.c
+++ b/src/drivers/spi/winbond.c
@@ -31,6 +31,8 @@
 #define CMD_W25_DP		0xb9	/* Deep Power-down */
 #define CMD_W25_RES		0xab	/* Release from DP, and Read Signature */
 #define CMD_W25_B_LOCK_STATUS	0x3d	/* Read Block/Sector Lock bit */
+#define CMD_W25_B_LOCK_SET	0x36	/* Set Block/Sector Lock bit */
+#define CMD_W25_B_LOCK_CLEAR	0x39	/* Clear Block/Sector Lock bit */
 
 struct winbond_spi_flash_params {
 	uint16_t	id;
@@ -319,9 +321,157 @@
 			return ret;
 	}
 	if (reg & STS_W25_WPS)
-		return winbond_read_b_lock_protection(flash, region);
+		return winbond_get_b_lock_protection(flash, region);
 	else
-		return winbond_read_b_protect_protection(flash, region);
+		return winbond_get_b_protect_protection(flash, region);
+}
+
+/*
+ * Only available on some devices.
+ * Set Block Protection Bits of each block.
+ *
+ * Returns:
+ * -1    on error
+ *  0    on success
+ */
+static int winbond_set_b_lock_protection(const struct spi_flash *flash,
+					 const struct region *region)
+{
+	int ret, i;
+	u8 cmd[5], reg8;
+
+	cmd[4] = 0x00;
+
+	/* Writeable */
+	cmd[0] = CMD_W25_B_LOCK_CLEAR;
+	for (i = 0; i < region->offset; i += flash->sector_size) {
+		cmd[1] = (i >> 16) & 0xff;
+		cmd[2] = (i >> 8) & 0xff;
+		cmd[3] = i & 0xff;
+
+		ret = spi_flash_cmd_ext(&flash->spi, cmd, sizeof(cmd),
+					 &reg8, sizeof(reg8));
+		if (ret)
+			return ret;
+	}
+
+	/* Readonly */
+	cmd[0] = CMD_W25_B_LOCK_SET;
+	for (i = 0; i < region->size; i += flash->sector_size) {
+		cmd[1] = ((region->offset + i) >> 16) & 0xff;
+		cmd[2] = ((region->offset + i) >> 8) & 0xff;
+		cmd[3] = (region->offset + i) & 0xff;
+
+		ret = spi_flash_cmd_ext(&flash->spi, cmd, sizeof(cmd),
+					 &reg8, sizeof(reg8));
+		if (ret)
+			return ret;
+	}
+
+	/* Writeable */
+	cmd[0] = CMD_W25_B_LOCK_CLEAR;
+	for (i = region->offset + region->size; i < flash->size;
+	     i += flash->sector_size) {
+		cmd[1] = (i >> 16) & 0xff;
+		cmd[2] = (i >> 8) & 0xff;
+		cmd[3] = i & 0xff;
+
+		ret = spi_flash_cmd_ext(&flash->spi, cmd, sizeof(cmd),
+					 &reg8, sizeof(reg8));
+		if (ret)
+			return ret;
+	}
+	return 1;
+}
+
+/*
+ * Available on all devices.
+ * Write block protect bits to Status/Status2 Reg.
+ *
+ * Returns:
+ * -1    on error
+ *  0    on success
+ */
+static int winbond_set_b_protect_protection(const struct spi_flash *flash,
+					    const struct region *region)
+{
+	int ret, shift, block;
+	union {
+		u8 u;
+		struct {
+			u8 busy : 1;
+			u8 wel  : 1;
+			u8 bp   : 3;
+			u8 tb   : 1;
+			u8 sec  : 1;
+			u8 srp0 : 1;
+		} s;
+	} reg1 = {.u = 0};
+	union {
+		u8 u;
+		struct {
+			u8 : 6;
+			u8 cmp  : 1;
+			u8 : 1;
+		} s;
+	} reg2 = {.u = 0};
+
+	/* Need to touch TOP or BOTTOM */
+	if (region->offset == 0 ||
+	    region->offset + region->size == flash->size)
+		return -1;
+
+	reg1.s.tb = region->offset == 0;
+
+	reg1.s.sec = region->size < flash->block_size;
+
+	if (reg1.s.sec && (region->size > flash->block_size / 2))
+		return -1;
+
+	if (reg1.s.sec)
+		block = flash->sector_size;
+	else
+		block = max(flash->block_size, flash->size / 64);
+
+	if (region->size > 0) {
+		for (shift = 0; shift <= 0x7; shift++) {
+			if (region->size == block << shift)
+				break;
+		}
+		if (shift > 0x7)
+			return -1;
+		reg1.s.bp = shift;
+	} else
+		reg1.s.bp = 0;
+
+	ret = spi_flash_cmd(&flash->spi, CMD_W25_WRSR, &reg1.u, sizeof(reg1.u));
+	if (ret)
+		return ret;
+
+	return spi_flash_cmd(&flash->spi, CMD_W25_WRSR2, &reg2.u,
+				    sizeof(reg2.u));
+}
+
+static int winbond_set_write_protection(const struct spi_flash *flash,
+					const struct region *region)
+{
+	u8 reg = STS_W25_WPS;
+
+	/* Check alignment */
+	if (region->offset & (flash->sector_size - 1))
+		return -1;
+	if (region->size & (flash->sector_size - 1))
+		return -1;
+
+	if (IS_ENABLED(CONFIG_SPI_FLASH_HAS_BLOCK_LOCK_BITS)) {
+		int ret = spi_flash_cmd(&flash->spi, CMD_W25_WRSR3, &reg,
+					sizeof(reg));
+		if (ret)
+			return ret;
+		return winbond_set_b_lock_protection(flash, region);
+	}
+
+	return winbond_set_b_protect_protection(flash, region);
 }
 
 static const struct spi_flash_ops spi_flash_ops = {
@@ -334,6 +484,7 @@
 	.read = spi_flash_cmd_read_fast,
 #endif
 	.get_write_protection = winbond_get_write_protection,
+	.set_write_protection = winbond_set_write_protection,
 };
 
 int spi_flash_probe_winbond(const struct spi_slave *spi, u8 *idcode,
diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h
index 82705d4..d1dfa92 100644
--- a/src/include/spi_flash.h
+++ b/src/include/spi_flash.h
@@ -42,7 +42,8 @@
 	int (*status)(const struct spi_flash *flash, u8 *reg);
 	int (*get_write_protection)(const struct spi_flash *flash,
 				    const struct region *region);
-
+	int (*set_write_protection)(const struct spi_flash *flash,
+				    const struct region *region);
 };
 
 struct spi_flash {
@@ -113,6 +114,25 @@
 int spi_flash_is_write_protected(const struct spi_flash *flash,
 				 const struct region *region);
 /*
+ * Enable the vendor dependent SPI flash write protection. The region not
+ * covered by write-protection will be set to write-able state.
+ * Only a single write-protected region is supported.
+ * Some flash ICs require the region to be aligned in the block size, sector
+ * size or page size.
+ * Some flash ICs require the region to start at TOP or BOTTOM.
+ *
+ * @param flash : A SPI flash device
+ * @param region: A subregion of the device's region
+ *
+ * Returns:
+ *  -1   on error
+ *  -1   if the region alignment is bad
+ *   0   on success
+ */
+int spi_flash_set_write_protected(const struct spi_flash *flash,
+				  const struct region *region);
+
+/*
  * Some SPI controllers require exclusive access to SPI flash when volatile
  * operations like erase or write are being performed. In such cases,
  * volatile_group_begin will gain exclusive access to SPI flash if not already

-- 
To view, visit https://review.coreboot.org/25105
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie3765b013855538eca37bc7800d3f9d5d09b8402
Gerrit-Change-Number: 25105
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <patrick.rudolph at 9elements.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180312/184a98a4/attachment-0001.html>


More information about the coreboot-gerrit mailing list