[U-Boot] [PATCH v2 1/5] spi_sf: Skip the erasing of protected sectors

Otavio Salvador otavio at ossystems.com.br
Sat Sep 12 15:57:32 CEST 2015


Many SPI flashes have protection bits (BP2, BP1 and BP0) in the
status register that can protect selected regions of the SPI NOR.

Take these bits into account when performing erase operations,
making sure that the protected areas are skipped.

Introduce the CONFIG_SPI_NOR_PROTECTION_STM option that can be selected
by systems that want to protect selected regions of SPI NOR flash using
the same programming model as in the ST Micro SPI NOR flashes, like
for example M25P32.

Cc: Jagan Teki <jteki at openedev.com>
Signed-off-by: Otavio Salvador <otavio at ossystems.com.br>
Tested-by: Fabio Estevam <fabio.estevam at freescale.com>
---
Changes since v1:
- Use CONFIG_SPI_NOR_PROTECTION_STM to make clear that the bit protection
bits follow the same programming model as in the ST Micro SPI NOR flashes
like M25P32.
- Improve the README entry addressing the questions made by Jagan

 README                     | 14 +++++++
 drivers/mtd/spi/sf_ops.c   | 91 ++++++++++++++++++++++++++++++++++++++++++++--
 drivers/mtd/spi/sf_probe.c |  2 +
 3 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/README b/README
index 1acc355..a45dfcd 100644
--- a/README
+++ b/README
@@ -2751,6 +2751,20 @@ CBFS (Coreboot Filesystem) support
 		Timeout for waiting until spi transfer completed.
 		default: (CONFIG_SYS_HZ/100)     /* 10 ms */
 
+		CONFIG_SPI_NOR_PROTECTION_STM
+		Enable the built-in protection mechanism provided by the
+		BP2, BP1 and BP0 bits from the status register present
+		on ST-Micro flashes such as M25P32. Please refer to the
+		M25P32 datasheet to understand how to program these bits
+		in order to protect a selected region of the SPI NOR flash.
+		This same bit protection programming model applies to SPI
+		NOR flashes from other manufacturers such as:
+		- Micron M25P32
+		- SST SST25VF032B
+		In order to program the bit protection bits of the status
+		register the spi_flash_cmd_write_status() function can be
+		used.
+
 - FPGA Support: CONFIG_FPGA
 
 		Enables FPGA subsystem.
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index 900ec1f..e53dcdc 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -264,6 +264,84 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 	return ret;
 }
 
+#ifdef CONFIG_SPI_NOR_PROTECTION_STM
+static int is_protected(struct spi_flash *flash, u32 offset)
+{
+	int total_sector, ret, protected_sector;
+	bool *protected;
+	u8 sr;
+
+	total_sector = flash->size / flash->erase_size;
+	protected = calloc(1, total_sector);
+	if (!protected)
+		return -ENOMEM;
+
+	ret = spi_flash_cmd_read_status(flash, &sr);
+	if (ret < 0)
+		goto free_protected;
+
+	/* Extract the protection bits: BP2, BP1 and BP0 */
+	sr = (sr & 0x1c) >> 2;
+
+	switch (sr) {
+	case 0:
+		protected_sector = 0;
+	break;
+
+	case 1:
+		protected_sector = total_sector / 64;
+	break;
+
+	case 2:
+		protected_sector = total_sector / 32;
+	break;
+
+	case 3:
+		protected_sector = total_sector / 16;
+	break;
+
+	case 4:
+		protected_sector = total_sector / 8;
+	break;
+
+	case 5:
+		protected_sector = total_sector / 4;
+	break;
+
+	case 6:
+		protected_sector = total_sector / 2;
+	break;
+
+	case 7:
+		protected_sector = total_sector;
+	break;
+
+	default:
+		ret = -EINVAL;
+		goto free_protected;
+	}
+
+	while (protected_sector) {
+		protected[total_sector - protected_sector] = 1;
+		protected_sector--;
+	}
+
+	if (protected[offset/flash->erase_size])
+		return 1;
+	else
+		return 0;
+
+free_protected:
+	free(protected);
+	return ret;
+}
+#else
+static int is_protected(struct spi_flash *flash, u32 offset)
+{
+	return 0;
+}
+#endif
+
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 {
 	u32 erase_size, erase_addr;
@@ -294,10 +372,17 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
 		      cmd[2], cmd[3], erase_addr);
 
-		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
-		if (ret < 0) {
-			debug("SF: erase failed\n");
+		if (is_protected(flash, offset) > 0) {
+			printf("Skipping to erase protected offset 0x%x\n",
+			       offset);
 			break;
+		} else {
+			ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
+						     NULL, 0);
+			if (ret < 0) {
+				debug("SF: erase failed\n");
+				break;
+			}
 		}
 
 		offset += erase_size;
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 954376d..c1d188f 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -256,12 +256,14 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
 	}
 #endif
 
+#if !defined(CONFIG_SPI_NOR_PROTECTION_STM)
 	/* Flash powers up read-only, so clear BP# bits */
 #if defined(CONFIG_SPI_FLASH_ATMEL) || \
 	defined(CONFIG_SPI_FLASH_MACRONIX) || \
 	defined(CONFIG_SPI_FLASH_SST)
 		spi_flash_cmd_write_status(flash, 0);
 #endif
+#endif
 
 	return 0;
 }
-- 
1.9.1



More information about the U-Boot mailing list