[U-Boot] [PATCH v6 15/16] sf: Add SPI protection mechanism from the kernel

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 */

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);

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

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! :-)

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-...

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-...
Yes, just tested your branch and it is working fine on my mx6sabread board.
Thanks!
participants (2)
-
Fabio Estevam
-
Jagan Teki