All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v6 15/16] sf: Add SPI protection mechanism from the kernel
@ 2015-11-03 16:17 Jagan Teki
  2015-11-03 16:17 ` [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism Jagan Teki
  0 siblings, 1 reply; 6+ messages in thread
From: Jagan Teki @ 2015-11-03 16:17 UTC (permalink / raw)
  To: u-boot

From: Fabio Estevam <fabio.estevam@freescale.com>

Add the SPI NOR protection mechanism from the kernel.

This code is based on the work from
Brian Norris <computersforpeace@gmail.com>
Here is the commit details.
"mtd: spi-nor: refactor block protection functions"
(sha1: 62593cf40b23b523b9fc9334ca61ba6c595ebb09)

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
[Added more details to commit message]
Signed-off-by: Jagan Teki <jteki@openedev.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
Reviewed-by: Jagan Teki <jteki@openedev.com>
---
Changes for v2:
	- Updated commit message
	
 drivers/mtd/spi/sf_internal.h |   3 +
 drivers/mtd/spi/sf_ops.c      | 170 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 173 insertions(+)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 8a3e5ec..ac493f1 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -105,6 +105,9 @@ enum spi_nor_option_flags {
 #define STATUS_QEB_WINSPAN		(1 << 1)
 #define STATUS_QEB_MXIC		(1 << 6)
 #define STATUS_PEC			(1 << 7)
+#define SR_BP0				BIT(2)  /* Block protect 0 */
+#define SR_BP1				BIT(3)  /* Block protect 1 */
+#define SR_BP2				BIT(4)  /* Block protect 2 */
 
 /* Flash timeout values */
 #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index f2a9244..4ada13f 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -15,6 +15,7 @@
 #include <spi_flash.h>
 #include <watchdog.h>
 #include <linux/compiler.h>
+#include <linux/log2.h>
 
 #include "sf_internal.h"
 
@@ -565,3 +566,172 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
 	return ret;
 }
 #endif
+
+#ifdef CONFIG_SPI_FLASH_STMICRO
+static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs,
+				 u32 *len)
+{
+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+	int shift = ffs(mask) - 1;
+	int pow;
+
+	if (!(sr & mask)) {
+		/* No protection */
+		*ofs = 0;
+		*len = 0;
+	} else {
+		pow = ((sr & mask) ^ mask) >> shift;
+		*len = flash->size >> pow;
+		*ofs = flash->size - *len;
+	}
+}
+
+/*
+ * Return 1 if the entire region is locked, 0 otherwise
+ */
+static int stm_is_locked_sr(struct spi_flash *flash, loff_t ofs, u32 len,
+			    u8 sr)
+{
+	loff_t lock_offs;
+	u32 lock_len;
+
+	stm_get_locked_range(flash, sr, &lock_offs, &lock_len);
+
+	return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+}
+
+/*
+ * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * more info.
+ *
+ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * negative on errors.
+ */
+int stm_is_locked(struct spi_flash *flash, loff_t ofs, u32 len)
+{
+	int status;
+	u8 sr;
+
+	status = spi_flash_cmd_read_status(flash, &sr);
+	if (status < 0)
+		return status;
+
+	return stm_is_locked_sr(flash, ofs, len, sr);
+}
+
+/*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+ * Supports only the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+ *   - TB: top/bottom protect - only handle TB=0 (top protect)
+ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
+ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
+ *  --------------------------------------------------------------------------
+ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
+ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
+ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
+ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
+ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
+ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
+ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
+ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
+ *
+ * Returns negative on errors, 0 on success.
+ */
+int stm_lock(struct spi_flash *flash, u32 ofs, u32 len)
+{
+	u8 status_old, status_new;
+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+	u8 shift = ffs(mask) - 1, pow, val;
+
+	spi_flash_cmd_read_status(flash, &status_old);
+
+	/* SPI NOR always locks to the end */
+	if (ofs + len != flash->size) {
+		/* Does combined region extend to end? */
+		if (!stm_is_locked_sr(flash, ofs + len, flash->size - ofs - len,
+				      status_old))
+			return -EINVAL;
+		len = flash->size - ofs;
+	}
+
+	/*
+	 * Need smallest pow such that:
+	 *
+	 *   1 / (2^pow) <= (len / size)
+	 *
+	 * so (assuming power-of-2 size) we do:
+	 *
+	 *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+	 */
+	pow = ilog2(flash->size) - ilog2(len);
+	val = mask - (pow << shift);
+	if (val & ~mask)
+		return -EINVAL;
+
+	/* Don't "lock" with no region! */
+	if (!(val & mask))
+		return -EINVAL;
+
+	status_new = (status_old & ~mask) | val;
+
+	/* Only modify protection if it will not unlock other areas */
+	if ((status_new & mask) <= (status_old & mask))
+		return -EINVAL;
+
+	spi_flash_cmd_write_status(flash, status_new);
+
+	return 0;
+}
+
+/*
+ * Unlock a region of the flash. See stm_lock() for more info
+ *
+ * Returns negative on errors, 0 on success.
+ */
+int stm_unlock(struct spi_flash *flash, u32 ofs, u32 len)
+{
+	uint8_t status_old, status_new;
+	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+	u8 shift = ffs(mask) - 1, pow, val;
+
+	spi_flash_cmd_read_status(flash, &status_old);
+
+	/* Cannot unlock; would unlock larger region than requested */
+	if (stm_is_locked_sr(flash, status_old, ofs - flash->erase_size,
+			     flash->erase_size))
+		return -EINVAL;
+	/*
+	 * Need largest pow such that:
+	 *
+	 *   1 / (2^pow) >= (len / size)
+	 *
+	 * so (assuming power-of-2 size) we do:
+	 *
+	 *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+	 */
+	pow = ilog2(flash->size) - order_base_2(flash->size - (ofs + len));
+	if (ofs + len == flash->size) {
+		val = 0; /* fully unlocked */
+	} else {
+		val = mask - (pow << shift);
+		/* Some power-of-two sizes are not supported */
+		if (val & ~mask)
+			return -EINVAL;
+	}
+
+	status_new = (status_old & ~mask) | val;
+
+	/* Only modify protection if it will not lock other areas */
+	if ((status_new & mask) >= (status_old & mask))
+		return -EINVAL;
+
+	spi_flash_cmd_write_status(flash, status_new);
+
+	return 0;
+}
+#endif  /* CONFIG_SPI_FLASH_STMICRO */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism
  2015-11-03 16:17 [U-Boot] [PATCH v6 15/16] sf: Add SPI protection mechanism from the kernel Jagan Teki
@ 2015-11-03 16:17 ` Jagan Teki
  2015-11-03 16:23   ` Jagan Teki
  0 siblings, 1 reply; 6+ messages in thread
From: Jagan Teki @ 2015-11-03 16:17 UTC (permalink / raw)
  To: u-boot

From: Fabio Estevam <fabio.estevam@freescale.com>

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.

Tested on a mx6qsabresd:

=> sf probe
SF: Detected M25P32 with page size 256 Bytes, erase size 64 KiB, total 4 MiB
=> sf protect lock  0x3f0000 0x10000
=> sf erase 0x3f0000 0x10000
offset 0x3f0000 is protected and cannot be erased
SF: 65536 bytes @ 0x3f0000 Erased: ERROR
=> sf protect unlock  0x3f0000 0x10000
=> sf erase 0x3f0000 0x10000
SF: 65536 bytes @ 0x3f0000 Erased: OK

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
[re-worked to fit the lock common to dm and non-dm]
Signed-off-by: Jagan Teki <jteki@openedev.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
Reviewed-by: Jagan Teki <jteki@openedev.com>
---
Changes for v6:
	- Updated commit message head
	- re-worked the code to fit the lock common to dm and non-dm

 common/cmd_sf.c               | 35 +++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/sf_internal.h |  9 +++++++++
 drivers/mtd/spi/sf_ops.c      | 14 ++++++++++++--
 drivers/mtd/spi/sf_probe.c    | 13 +++++++++++++
 include/spi_flash.h           | 19 +++++++++++++++++++
 5 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index ac7f5df..42862d9 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -348,6 +348,37 @@ static int do_spi_flash_erase(int argc, char * const argv[])
 	return ret == 0 ? 0 : 1;
 }
 
+static int do_spi_protect(int argc, char * const argv[])
+{
+	int ret = 0;
+	loff_t start, len;
+	bool prot = false;
+
+	if (argc != 4)
+		return -1;
+
+	if (!str2off(argv[2], &start)) {
+		puts("start sector is not a valid number\n");
+		return 1;
+	}
+
+	if (!str2off(argv[3], &len)) {
+		puts("len is not a valid number\n");
+		return 1;
+	}
+
+	if (strcmp(argv[1], "lock") == 0)
+		prot = true;
+	else if (strcmp(argv[1], "unlock") == 0)
+		prot = false;
+	else
+		return -1;  /* Unknown parameter */
+
+	ret = spi_flash_protect(flash, start, len, prot);
+
+	return ret == 0 ? 0 : 1;
+}
+
 #ifdef CONFIG_CMD_SF_TEST
 enum {
 	STAGE_ERASE,
@@ -540,6 +571,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
 		ret = do_spi_flash_read_write(argc, argv);
 	else if (strcmp(cmd, "erase") == 0)
 		ret = do_spi_flash_erase(argc, argv);
+	else if (strcmp(cmd, "protect") == 0)
+		ret = do_spi_protect(argc, argv);
 #ifdef CONFIG_CMD_SF_TEST
 	else if (!strcmp(cmd, "test"))
 		ret = do_spi_flash_test(argc, argv);
@@ -579,5 +612,7 @@ U_BOOT_CMD(
 	"sf update addr offset|partition len	- erase and write `len' bytes from memory\n"
 	"					  at `addr' to flash at `offset'\n"
 	"					  or to start of mtd `partition'\n"
+	"sf protect lock/unlock sector len	- protect/unprotect 'len' bytes starting\n"
+	"					  at address 'sector'\n"
 	SF_TEST_HELP
 );
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index ac493f1..8793f18 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -176,6 +176,15 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs);
 /* Program the status register */
 int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws);
 
+/* Lock stmicro spi flash region */
+int stm_lock(struct spi_flash *flash, u32 ofs, size_t len);
+
+/* Unlock stmicro spi flash region */
+int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len);
+
+/* Check if a stmicro spi flash region is completely locked */
+int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len);
+
 /* Read the config register */
 int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc);
 
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index 4ada13f..31c79c6 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -268,6 +268,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
 		return -1;
 	}
 
+	if (flash->flash_is_locked(flash, offset, len) > 0) {
+		printf("offset 0x%x is protected and cannot be erased\n", offset);
+		return -EINVAL;
+	}
+
 	cmd[0] = flash->erase_cmd;
 	while (len) {
 		erase_addr = offset;
@@ -310,6 +315,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 
 	page_size = flash->page_size;
 
+	if (flash->flash_is_locked(flash, offset, len) > 0) {
+		printf("offset 0x%x is protected and cannot be written\n", offset);
+		return -EINVAL;
+	}
+
 	cmd[0] = flash->write_cmd;
 	for (actual = 0; actual < len; actual += chunk_len) {
 		write_addr = offset;
@@ -589,7 +599,7 @@ static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs,
 /*
  * Return 1 if the entire region is locked, 0 otherwise
  */
-static int stm_is_locked_sr(struct spi_flash *flash, loff_t ofs, u32 len,
+static int stm_is_locked_sr(struct spi_flash *flash, u32 ofs, u32 len,
 			    u8 sr)
 {
 	loff_t lock_offs;
@@ -607,7 +617,7 @@ static int stm_is_locked_sr(struct spi_flash *flash, loff_t ofs, u32 len,
  * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
  * negative on errors.
  */
-int stm_is_locked(struct spi_flash *flash, loff_t ofs, u32 len)
+int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
 {
 	int status;
 	u8 sr;
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index c000c53..bc05d30 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -182,6 +182,19 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
 	flash->read = spi_flash_cmd_read_ops;
 #endif
 
+	/* lock hooks are flash specific - assign them based on idcode0 */
+	switch (idcode[0]) {
+#ifdef CONFIG_SPI_FLASH_STMICRO
+	case SPI_FLASH_CFI_MFR_STMICRO:
+		flash->flash_lock = stm_lock;
+		flash->flash_unlock = stm_unlock;
+		flash->flash_is_locked = stm_is_locked;
+#endif
+		break;
+	default:
+		debug("SF: Lock ops not supported for %02x flash\n", idcode[0]);
+	}
+
 	/* Compute the flash size */
 	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
 	/*
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 4312d3d..0ae0062 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -54,6 +54,9 @@ struct spi_slave;
  * @write_cmd:		Write cmd - page and quad program.
  * @dummy_byte:		Dummy cycles for read operation.
  * @memory_map:		Address of read-only SPI flash access
+ * @flash_lock:		lock a region of the SPI Flash
+ * @flash_unlock:	unlock a region of the SPI Flash
+ * @flash_is_locked:	check if a region of the SPI Flash is completely locked
  * @read:		Flash read ops: Read len bytes at offset into buf
  *			Supported cmds: Fast Array Read
  * @write:		Flash write ops: Write len bytes from buf into offset
@@ -87,6 +90,10 @@ struct spi_flash {
 	u8 dummy_byte;
 
 	void *memory_map;
+
+	int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len);
+	int (*flash_unlock)(struct spi_flash *flash, u32 ofs, size_t len);
+	int (*flash_is_locked)(struct spi_flash *flash, u32 ofs, size_t len);
 #ifndef CONFIG_DM_SPI_FLASH
 	/*
 	 * These are not strictly needed for driver model, but keep them here
@@ -227,6 +234,18 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
 }
 #endif
 
+static inline int spi_flash_protect(struct spi_flash *flash, u32 ofs, u32 len,
+					bool prot)
+{
+	if (!flash->flash_lock)
+		return -EOPNOTSUPP;
+
+	if (prot)
+		return flash->flash_lock(flash, ofs, len);
+	else
+		return flash->flash_unlock(flash, ofs, len);
+}
+
 void spi_boot(void) __noreturn;
 void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism
  2015-11-03 16:17 ` [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism Jagan Teki
@ 2015-11-03 16:23   ` Jagan Teki
  2015-11-03 16:32     ` Fabio Estevam
  0 siblings, 1 reply; 6+ messages in thread
From: Jagan Teki @ 2015-11-03 16:23 UTC (permalink / raw)
  To: u-boot

Fabio,

Let me know you inputs I will add pick 14-patches with v4 and these two.

On 3 November 2015 at 21:47, Jagan Teki <jteki@openedev.com> wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
>
> 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.
>
> Tested on a mx6qsabresd:
>
> => sf probe
> SF: Detected M25P32 with page size 256 Bytes, erase size 64 KiB, total 4 MiB
> => sf protect lock  0x3f0000 0x10000
> => sf erase 0x3f0000 0x10000
> offset 0x3f0000 is protected and cannot be erased
> SF: 65536 bytes @ 0x3f0000 Erased: ERROR
> => sf protect unlock  0x3f0000 0x10000
> => sf erase 0x3f0000 0x10000
> SF: 65536 bytes @ 0x3f0000 Erased: OK
>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> [re-worked to fit the lock common to dm and non-dm]
> Signed-off-by: Jagan Teki <jteki@openedev.com>
> Reviewed-by: Tom Rini <trini@konsulko.com>
> Reviewed-by: Heiko Schocher <hs@denx.de>
> Reviewed-by: Jagan Teki <jteki@openedev.com>
> ---
> Changes for v6:
>         - Updated commit message head
>         - re-worked the code to fit the lock common to dm and non-dm
>
>  common/cmd_sf.c               | 35 +++++++++++++++++++++++++++++++++++
>  drivers/mtd/spi/sf_internal.h |  9 +++++++++
>  drivers/mtd/spi/sf_ops.c      | 14 ++++++++++++--
>  drivers/mtd/spi/sf_probe.c    | 13 +++++++++++++
>  include/spi_flash.h           | 19 +++++++++++++++++++
>  5 files changed, 88 insertions(+), 2 deletions(-)
>
> diff --git a/common/cmd_sf.c b/common/cmd_sf.c
> index ac7f5df..42862d9 100644
> --- a/common/cmd_sf.c
> +++ b/common/cmd_sf.c
> @@ -348,6 +348,37 @@ static int do_spi_flash_erase(int argc, char * const argv[])
>         return ret == 0 ? 0 : 1;
>  }
>
> +static int do_spi_protect(int argc, char * const argv[])
> +{
> +       int ret = 0;
> +       loff_t start, len;
> +       bool prot = false;
> +
> +       if (argc != 4)
> +               return -1;
> +
> +       if (!str2off(argv[2], &start)) {
> +               puts("start sector is not a valid number\n");
> +               return 1;
> +       }
> +
> +       if (!str2off(argv[3], &len)) {
> +               puts("len is not a valid number\n");
> +               return 1;
> +       }
> +
> +       if (strcmp(argv[1], "lock") == 0)
> +               prot = true;
> +       else if (strcmp(argv[1], "unlock") == 0)
> +               prot = false;
> +       else
> +               return -1;  /* Unknown parameter */
> +
> +       ret = spi_flash_protect(flash, start, len, prot);
> +
> +       return ret == 0 ? 0 : 1;
> +}
> +
>  #ifdef CONFIG_CMD_SF_TEST
>  enum {
>         STAGE_ERASE,
> @@ -540,6 +571,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
>                 ret = do_spi_flash_read_write(argc, argv);
>         else if (strcmp(cmd, "erase") == 0)
>                 ret = do_spi_flash_erase(argc, argv);
> +       else if (strcmp(cmd, "protect") == 0)
> +               ret = do_spi_protect(argc, argv);
>  #ifdef CONFIG_CMD_SF_TEST
>         else if (!strcmp(cmd, "test"))
>                 ret = do_spi_flash_test(argc, argv);
> @@ -579,5 +612,7 @@ U_BOOT_CMD(
>         "sf update addr offset|partition len    - erase and write `len' bytes from memory\n"
>         "                                         at `addr' to flash at `offset'\n"
>         "                                         or to start of mtd `partition'\n"
> +       "sf protect lock/unlock sector len      - protect/unprotect 'len' bytes starting\n"
> +       "                                         at address 'sector'\n"
>         SF_TEST_HELP
>  );
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index ac493f1..8793f18 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -176,6 +176,15 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs);
>  /* Program the status register */
>  int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws);
>
> +/* Lock stmicro spi flash region */
> +int stm_lock(struct spi_flash *flash, u32 ofs, size_t len);
> +
> +/* Unlock stmicro spi flash region */
> +int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len);
> +
> +/* Check if a stmicro spi flash region is completely locked */
> +int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len);
> +
>  /* Read the config register */
>  int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc);
>
> diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
> index 4ada13f..31c79c6 100644
> --- a/drivers/mtd/spi/sf_ops.c
> +++ b/drivers/mtd/spi/sf_ops.c
> @@ -268,6 +268,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
>                 return -1;
>         }
>
> +       if (flash->flash_is_locked(flash, offset, len) > 0) {
> +               printf("offset 0x%x is protected and cannot be erased\n", offset);
> +               return -EINVAL;
> +       }
> +
>         cmd[0] = flash->erase_cmd;
>         while (len) {
>                 erase_addr = offset;
> @@ -310,6 +315,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
>
>         page_size = flash->page_size;
>
> +       if (flash->flash_is_locked(flash, offset, len) > 0) {
> +               printf("offset 0x%x is protected and cannot be written\n", offset);
> +               return -EINVAL;
> +       }
> +
>         cmd[0] = flash->write_cmd;
>         for (actual = 0; actual < len; actual += chunk_len) {
>                 write_addr = offset;
> @@ -589,7 +599,7 @@ static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs,
>  /*
>   * Return 1 if the entire region is locked, 0 otherwise
>   */
> -static int stm_is_locked_sr(struct spi_flash *flash, loff_t ofs, u32 len,
> +static int stm_is_locked_sr(struct spi_flash *flash, u32 ofs, u32 len,
>                             u8 sr)
>  {
>         loff_t lock_offs;
> @@ -607,7 +617,7 @@ static int stm_is_locked_sr(struct spi_flash *flash, loff_t ofs, u32 len,
>   * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
>   * negative on errors.
>   */
> -int stm_is_locked(struct spi_flash *flash, loff_t ofs, u32 len)
> +int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
>  {
>         int status;
>         u8 sr;
> diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
> index c000c53..bc05d30 100644
> --- a/drivers/mtd/spi/sf_probe.c
> +++ b/drivers/mtd/spi/sf_probe.c
> @@ -182,6 +182,19 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
>         flash->read = spi_flash_cmd_read_ops;
>  #endif
>
> +       /* lock hooks are flash specific - assign them based on idcode0 */
> +       switch (idcode[0]) {
> +#ifdef CONFIG_SPI_FLASH_STMICRO
> +       case SPI_FLASH_CFI_MFR_STMICRO:
> +               flash->flash_lock = stm_lock;
> +               flash->flash_unlock = stm_unlock;
> +               flash->flash_is_locked = stm_is_locked;
> +#endif
> +               break;
> +       default:
> +               debug("SF: Lock ops not supported for %02x flash\n", idcode[0]);
> +       }
> +
>         /* Compute the flash size */
>         flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
>         /*
> diff --git a/include/spi_flash.h b/include/spi_flash.h
> index 4312d3d..0ae0062 100644
> --- a/include/spi_flash.h
> +++ b/include/spi_flash.h
> @@ -54,6 +54,9 @@ struct spi_slave;
>   * @write_cmd:         Write cmd - page and quad program.
>   * @dummy_byte:                Dummy cycles for read operation.
>   * @memory_map:                Address of read-only SPI flash access
> + * @flash_lock:                lock a region of the SPI Flash
> + * @flash_unlock:      unlock a region of the SPI Flash
> + * @flash_is_locked:   check if a region of the SPI Flash is completely locked
>   * @read:              Flash read ops: Read len bytes at offset into buf
>   *                     Supported cmds: Fast Array Read
>   * @write:             Flash write ops: Write len bytes from buf into offset
> @@ -87,6 +90,10 @@ struct spi_flash {
>         u8 dummy_byte;
>
>         void *memory_map;
> +
> +       int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len);
> +       int (*flash_unlock)(struct spi_flash *flash, u32 ofs, size_t len);
> +       int (*flash_is_locked)(struct spi_flash *flash, u32 ofs, size_t len);
>  #ifndef CONFIG_DM_SPI_FLASH
>         /*
>          * These are not strictly needed for driver model, but keep them here
> @@ -227,6 +234,18 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
>  }
>  #endif
>
> +static inline int spi_flash_protect(struct spi_flash *flash, u32 ofs, u32 len,
> +                                       bool prot)
> +{
> +       if (!flash->flash_lock)
> +               return -EOPNOTSUPP;
> +
> +       if (prot)
> +               return flash->flash_lock(flash, ofs, len);
> +       else
> +               return flash->flash_unlock(flash, ofs, len);
> +}
> +
>  void spi_boot(void) __noreturn;
>  void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);
>
> --
> 1.9.1
>



-- 
Jagan | openedev.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism
  2015-11-03 16:23   ` Jagan Teki
@ 2015-11-03 16:32     ` Fabio Estevam
  2015-11-03 16:34       ` Jagan Teki
  0 siblings, 1 reply; 6+ messages in thread
From: Fabio Estevam @ 2015-11-03 16:32 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On Tue, Nov 3, 2015 at 2:23 PM, Jagan Teki <jteki@openedev.com> wrote:
> Fabio,
>
> Let me know you inputs I will add pick 14-patches with v4 and these two.

Looks good! Thanks a lot! :-)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism
  2015-11-03 16:32     ` Fabio Estevam
@ 2015-11-03 16:34       ` Jagan Teki
  2015-11-03 16:44         ` Fabio Estevam
  0 siblings, 1 reply; 6+ messages in thread
From: Jagan Teki @ 2015-11-03 16:34 UTC (permalink / raw)
  To: u-boot

On 3 November 2015 at 22:02, Fabio Estevam <festevam@gmail.com> wrote:
> Hi Jagan,
>
> On Tue, Nov 3, 2015 at 2:23 PM, Jagan Teki <jteki@openedev.com> wrote:
>> Fabio,
>>
>> Let me know you inputs I will add pick 14-patches with v4 and these two.
>
> Looks good! Thanks a lot! :-)

Can you test this branch [1] I will pull all these 16 patches.

[1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-lock

-- 
Jagan | openedev.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism
  2015-11-03 16:34       ` Jagan Teki
@ 2015-11-03 16:44         ` Fabio Estevam
  0 siblings, 0 replies; 6+ messages in thread
From: Fabio Estevam @ 2015-11-03 16:44 UTC (permalink / raw)
  To: u-boot

On Tue, Nov 3, 2015 at 2:34 PM, Jagan Teki <jteki@openedev.com> wrote:
> On 3 November 2015 at 22:02, Fabio Estevam <festevam@gmail.com> wrote:
>> Hi Jagan,
>>
>> On Tue, Nov 3, 2015 at 2:23 PM, Jagan Teki <jteki@openedev.com> wrote:
>>> Fabio,
>>>
>>> Let me know you inputs I will add pick 14-patches with v4 and these two.
>>
>> Looks good! Thanks a lot! :-)
>
> Can you test this branch [1] I will pull all these 16 patches.
>
> [1] http://git.denx.de/?p=u-boot/u-boot-spi.git;a=shortlog;h=refs/heads/spi-nor-lock

Yes, just tested your branch and it is working fine on my mx6sabread board.

Thanks!

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-11-03 16:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-03 16:17 [U-Boot] [PATCH v6 15/16] sf: Add SPI protection mechanism from the kernel Jagan Teki
2015-11-03 16:17 ` [U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism Jagan Teki
2015-11-03 16:23   ` Jagan Teki
2015-11-03 16:32     ` Fabio Estevam
2015-11-03 16:34       ` Jagan Teki
2015-11-03 16:44         ` Fabio Estevam

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.