[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),
+ ®8, 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),
+ ®8, 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),
+ ®8, 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, ®1.u, sizeof(reg1.u));
+ if (ret)
+ return ret;
+
+ return spi_flash_cmd(&flash->spi, CMD_W25_WRSR2, ®2.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, ®,
+ 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