aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/cmd_sf.c35
-rw-r--r--drivers/mtd/spi/sf_internal.h9
-rw-r--r--drivers/mtd/spi/sf_ops.c14
-rw-r--r--drivers/mtd/spi/sf_probe.c13
-rw-r--r--include/spi_flash.h19
5 files changed, 88 insertions, 2 deletions
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index ac7f5dfb818..42862d9d921 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 ac493f1f767..8793f1865a3 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 6c87ba60fde..d8324645b2c 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 c000c532741..bc05d302211 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 4312d3d691e..0ae0062d12f 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);