Message ID | 1445875918-14777-16-git-send-email-fabio.estevam@freescale.com |
---|---|
State | Superseded |
Delegated to: | Jagannadha Sutradharudu Teki |
Headers | show |
Hi Fabio, On 26 October 2015 at 21:41, Fabio Estevam <fabio.estevam@freescale.com> wrote: > 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> > Reviewed-by: Tom Rini <trini@konsulko.com> > Reviewed-by: Heiko Schocher <hs@denx.de> > --- > Changes since v3: > - None > > common/cmd_sf.c | 35 +++++++++++++++++++++++++++++++++++ > drivers/mtd/spi/sf-uclass.c | 8 ++++++++ > drivers/mtd/spi/sf_internal.h | 8 ++++++++ > drivers/mtd/spi/sf_ops.c | 25 +++++++++++++++++++++++++ > drivers/mtd/spi/sf_probe.c | 31 +++++++++++++++++++++++++++++++ > include/spi_flash.h | 41 +++++++++++++++++++++++++++++++++++++++++ > 6 files changed, 148 insertions(+) > > 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 Don't we have is_locked command from user? may be we can all this one as well. > + 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-uclass.c b/drivers/mtd/spi/sf-uclass.c > index 350e21a..7663885 100644 > --- a/drivers/mtd/spi/sf-uclass.c > +++ b/drivers/mtd/spi/sf-uclass.c > @@ -27,6 +27,14 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) > return sf_get_ops(dev)->erase(dev, offset, len); > } > > +int spi_flash_protect_dm(struct udevice *dev, u32 offset, size_t len, bool prot) > +{ > + if (prot) > + return sf_get_ops(dev)->lock(dev, offset, len); > + else > + return sf_get_ops(dev)->unlock(dev, offset, len); > +} > + > /* > * TODO(sjg@chromium.org): This is an old-style function. We should remove > * it when all SPI flash drivers use dm > diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h > index 9c95d56..33be598 100644 > --- a/drivers/mtd/spi/sf_internal.h > +++ b/drivers/mtd/spi/sf_internal.h > @@ -168,6 +168,10 @@ 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); > > +int stm_is_locked(struct spi_flash *nor, loff_t ofs, u32 len); > +int stm_lock(struct spi_flash *nor, u32 ofs, u32 len); > +int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len); > + > /* Read the config register */ > int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); > > @@ -222,6 +226,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, > int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, > size_t len, void *data); > > +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len); > +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len); > +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len); > + > #ifdef CONFIG_SPI_FLASH_MTD > int spi_flash_mtd_register(struct spi_flash *flash); > void spi_flash_mtd_unregister(void); > diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c > index 928f9c1..ee23bb2 100644 > --- a/drivers/mtd/spi/sf_ops.c > +++ b/drivers/mtd/spi/sf_ops.c > @@ -277,6 +277,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) > return -1; > } > > + if (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; > @@ -319,6 +324,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, > > page_size = flash->page_size; > > + if (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; > @@ -357,6 +367,21 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, > return ret; > } > > +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len) > +{ > + return stm_lock(flash, offset, len); > +} > + > +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len) > +{ > + return stm_unlock(flash, offset, len); > +} > + > +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len) > +{ > + return stm_is_locked(flash, offset, len); > +} > + > int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, > size_t cmd_len, void *data, size_t data_len) > { > diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c > index 954376d..0975a2f 100644 > --- a/drivers/mtd/spi/sf_probe.c > +++ b/drivers/mtd/spi/sf_probe.c > @@ -149,6 +149,11 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, > #endif > flash->erase = spi_flash_cmd_erase_ops; > flash->read = spi_flash_cmd_read_ops; > +#if defined(CONFIG_SPI_FLASH_STMICRO) > + flash->lock = spi_flash_cmd_lock_ops; > + flash->unlock = spi_flash_cmd_unlock_ops; > + flash->is_locked = spi_flash_cmd_is_locked_ops; > +#endif We need to check the idcode as well because if we compile other flash vendor with micron, non-micron flash got initialized with these lock ops' and also assign stm_* calls if the idcode is micro. > #endif > > /* Compute the flash size */ > @@ -469,6 +474,27 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) > return spi_flash_cmd_erase_ops(flash, offset, len); > } > > +int spi_flash_std_lock(struct udevice *dev, u32 offset, size_t len) > +{ > + struct spi_flash *flash = dev_get_uclass_priv(dev); > + > + return spi_flash_cmd_lock_ops(flash, offset, len); > +} > + > +int spi_flash_std_unlock(struct udevice *dev, u32 offset, size_t len) > +{ > + struct spi_flash *flash = dev_get_uclass_priv(dev); > + > + return spi_flash_cmd_unlock_ops(flash, offset, len); > +} > + > +int spi_flash_std_is_locked(struct udevice *dev, u32 offset, size_t len) > +{ > + struct spi_flash *flash = dev_get_uclass_priv(dev); > + > + return spi_flash_cmd_is_locked_ops(flash, offset, len); > +} > + > int spi_flash_std_probe(struct udevice *dev) > { > struct spi_slave *slave = dev_get_parentdata(dev); > @@ -485,6 +511,11 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = { > .read = spi_flash_std_read, > .write = spi_flash_std_write, > .erase = spi_flash_std_erase, > +#if defined(CONFIG_SPI_FLASH_STMICRO) > + .lock = spi_flash_std_lock, > + .unlock = spi_flash_std_unlock, > + .is_locked = spi_flash_std_is_locked, > +#endif This should be changes as I pointed above with non-dm, probably we can assign lock func_ptr's in probe by checking idcode. > }; > > static const struct udevice_id spi_flash_std_ids[] = { > diff --git a/include/spi_flash.h b/include/spi_flash.h > index 73b2b0a..4d55ba7 100644 > --- a/include/spi_flash.h > +++ b/include/spi_flash.h > @@ -110,6 +110,9 @@ struct spi_flash { > const void *buf); > int (*erase)(struct spi_flash *flash, u32 offset, size_t len); > #endif > + int (*lock)(struct spi_flash *flash, u32 offset, size_t len); > + int (*unlock)(struct spi_flash *flash, u32 offset, size_t len); > + int (*is_locked)(struct spi_flash *flash, u32 offset, size_t len); > }; > > struct dm_spi_flash_ops { > @@ -117,6 +120,9 @@ struct dm_spi_flash_ops { > int (*write)(struct udevice *dev, u32 offset, size_t len, > const void *buf); > int (*erase)(struct udevice *dev, u32 offset, size_t len); > + int (*lock)(struct udevice *dev, u32 offset, size_t len); > + int (*unlock)(struct udevice *dev, u32 offset, size_t len); > + int (*is_locked)(struct udevice *dev, u32 offset, size_t len); > }; > > /* Access the serial operations for a device */ > @@ -158,6 +164,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len, > */ > int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len); > > +/** > + * spi_flash_protect_dm() - Protect/unprotect blocks of the SPI flash > + * > + * Note that @len must be a muiltiple of the flash sector size. > + * > + * @dev: SPI flash device > + * @offset: Offset into device in bytes to start erasing > + * @len: Number of bytes to erase > + * @prot: True: lock the block or False: unlock the block > + * @return 0 if OK, -ve on error > + */ > +int spi_flash_protect_dm(struct udevice *dev, u32 offset, size_t len, > + bool prot); > + > int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, > unsigned int max_hz, unsigned int spi_mode, > struct udevice **devp); > @@ -189,6 +209,15 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, > return spi_flash_erase_dm(flash->dev, offset, len); > } > > +static inline int spi_flash_protect(struct spi_flash *flash, loff_t ofs, > + u32 len, bool prot) > +{ > + if (!flash->lock) > + return -EOPNOTSUPP; > + > + return spi_flash_protect_dm(flash->dev, ofs, len, prot); > +} > + > struct sandbox_state; > > int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, > @@ -231,6 +260,18 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, > { > return flash->erase(flash, offset, len); > } > + > +static inline int spi_flash_protect(struct spi_flash *flash, u32 ofs, u32 len, > + bool prot) > +{ > + if (!flash->lock) > + return -EOPNOTSUPP; > + > + if (prot) > + return flash->lock(flash, ofs, len); > + else > + return flash->unlock(flash, ofs, len); > +} > #endif > > void spi_boot(void) __noreturn; > -- > 1.9.1 > thanks!
Hi Jagan, On Fri, Oct 30, 2015 at 2:28 PM, Jagan Teki <jteki@openedev.com> wrote: >> +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 > > Don't we have is_locked command from user? may be we can all this one as well. Sorry, I did not understand the suggestion here. Looks like you are happy with patches 1 to 15 of this series. Could you please apply patches 1 to 15 and then I rework only this last one?
Hi Fabio, On 30 October 2015 at 22:21, Fabio Estevam <festevam@gmail.com> wrote: > Hi Jagan, > > On Fri, Oct 30, 2015 at 2:28 PM, Jagan Teki <jteki@openedev.com> wrote: > >>> +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 >> >> Don't we have is_locked command from user? may be we can all this one as well. > > Sorry, I did not understand the suggestion here. > > Looks like you are happy with patches 1 to 15 of this series. > > Could you please apply patches 1 to 15 and then I rework only this last one? I will pick the entire series once, since 15/16 and 16/16 are same feature set. My questions with 16/16 is 1. We need to check the idcode as well because if we compile other flash vendor with micron, non micron flash got initialized with these lock ops' and also assign stm_* calls if the idcode is micro. > +#if defined(CONFIG_SPI_FLASH_STMICRO) > + flash->lock = spi_flash_cmd_lock_ops; > + flash->unlock = spi_flash_cmd_unlock_ops; > + flash->is_locked = spi_flash_cmd_is_locked_ops; > +#endif 2. Do the 1 for dm as well, probably in probe. 3. What about adding 'sf protect is_locked' since we have code already? thanks!
On Fri, Oct 30, 2015 at 4:23 PM, Jagan Teki <jteki@openedev.com> wrote: >> Looks like you are happy with patches 1 to 15 of this series. >> >> Could you please apply patches 1 to 15 and then I rework only this last one? > > I will pick the entire series once, since 15/16 and 16/16 are same feature set. Hopefully that will happen some day soon :-) > > My questions with 16/16 is > > 1. We need to check the idcode as well because if we compile other > flash vendor with micron, non > micron flash got initialized with these lock ops' and also assign > stm_* calls if the idcode is micro. Done in v5. > >> +#if defined(CONFIG_SPI_FLASH_STMICRO) >> + flash->lock = spi_flash_cmd_lock_ops; >> + flash->unlock = spi_flash_cmd_unlock_ops; >> + flash->is_locked = spi_flash_cmd_is_locked_ops; >> +#endif > > 2. Do the 1 for dm as well, probably in probe. Done in v5. > 3. What about adding 'sf protect is_locked' since we have code already? We can add this later if someone thinks it is really needed.
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-uclass.c b/drivers/mtd/spi/sf-uclass.c index 350e21a..7663885 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -27,6 +27,14 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) return sf_get_ops(dev)->erase(dev, offset, len); } +int spi_flash_protect_dm(struct udevice *dev, u32 offset, size_t len, bool prot) +{ + if (prot) + return sf_get_ops(dev)->lock(dev, offset, len); + else + return sf_get_ops(dev)->unlock(dev, offset, len); +} + /* * TODO(sjg@chromium.org): This is an old-style function. We should remove * it when all SPI flash drivers use dm diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 9c95d56..33be598 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -168,6 +168,10 @@ 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); +int stm_is_locked(struct spi_flash *nor, loff_t ofs, u32 len); +int stm_lock(struct spi_flash *nor, u32 ofs, u32 len); +int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len); + /* Read the config register */ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); @@ -222,6 +226,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data); +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len); +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len); +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len); + #ifdef CONFIG_SPI_FLASH_MTD int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index 928f9c1..ee23bb2 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -277,6 +277,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) return -1; } + if (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; @@ -319,6 +324,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, page_size = flash->page_size; + if (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; @@ -357,6 +367,21 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, return ret; } +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + return stm_lock(flash, offset, len); +} + +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + return stm_unlock(flash, offset, len); +} + +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + return stm_is_locked(flash, offset, len); +} + int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 954376d..0975a2f 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -149,6 +149,11 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, #endif flash->erase = spi_flash_cmd_erase_ops; flash->read = spi_flash_cmd_read_ops; +#if defined(CONFIG_SPI_FLASH_STMICRO) + flash->lock = spi_flash_cmd_lock_ops; + flash->unlock = spi_flash_cmd_unlock_ops; + flash->is_locked = spi_flash_cmd_is_locked_ops; +#endif #endif /* Compute the flash size */ @@ -469,6 +474,27 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) return spi_flash_cmd_erase_ops(flash, offset, len); } +int spi_flash_std_lock(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_lock_ops(flash, offset, len); +} + +int spi_flash_std_unlock(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_unlock_ops(flash, offset, len); +} + +int spi_flash_std_is_locked(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_is_locked_ops(flash, offset, len); +} + int spi_flash_std_probe(struct udevice *dev) { struct spi_slave *slave = dev_get_parentdata(dev); @@ -485,6 +511,11 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = { .read = spi_flash_std_read, .write = spi_flash_std_write, .erase = spi_flash_std_erase, +#if defined(CONFIG_SPI_FLASH_STMICRO) + .lock = spi_flash_std_lock, + .unlock = spi_flash_std_unlock, + .is_locked = spi_flash_std_is_locked, +#endif }; static const struct udevice_id spi_flash_std_ids[] = { diff --git a/include/spi_flash.h b/include/spi_flash.h index 73b2b0a..4d55ba7 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -110,6 +110,9 @@ struct spi_flash { const void *buf); int (*erase)(struct spi_flash *flash, u32 offset, size_t len); #endif + int (*lock)(struct spi_flash *flash, u32 offset, size_t len); + int (*unlock)(struct spi_flash *flash, u32 offset, size_t len); + int (*is_locked)(struct spi_flash *flash, u32 offset, size_t len); }; struct dm_spi_flash_ops { @@ -117,6 +120,9 @@ struct dm_spi_flash_ops { int (*write)(struct udevice *dev, u32 offset, size_t len, const void *buf); int (*erase)(struct udevice *dev, u32 offset, size_t len); + int (*lock)(struct udevice *dev, u32 offset, size_t len); + int (*unlock)(struct udevice *dev, u32 offset, size_t len); + int (*is_locked)(struct udevice *dev, u32 offset, size_t len); }; /* Access the serial operations for a device */ @@ -158,6 +164,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len, */ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len); +/** + * spi_flash_protect_dm() - Protect/unprotect blocks of the SPI flash + * + * Note that @len must be a muiltiple of the flash sector size. + * + * @dev: SPI flash device + * @offset: Offset into device in bytes to start erasing + * @len: Number of bytes to erase + * @prot: True: lock the block or False: unlock the block + * @return 0 if OK, -ve on error + */ +int spi_flash_protect_dm(struct udevice *dev, u32 offset, size_t len, + bool prot); + int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, unsigned int max_hz, unsigned int spi_mode, struct udevice **devp); @@ -189,6 +209,15 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, return spi_flash_erase_dm(flash->dev, offset, len); } +static inline int spi_flash_protect(struct spi_flash *flash, loff_t ofs, + u32 len, bool prot) +{ + if (!flash->lock) + return -EOPNOTSUPP; + + return spi_flash_protect_dm(flash->dev, ofs, len, prot); +} + struct sandbox_state; int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, @@ -231,6 +260,18 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, { return flash->erase(flash, offset, len); } + +static inline int spi_flash_protect(struct spi_flash *flash, u32 ofs, u32 len, + bool prot) +{ + if (!flash->lock) + return -EOPNOTSUPP; + + if (prot) + return flash->lock(flash, ofs, len); + else + return flash->unlock(flash, ofs, len); +} #endif void spi_boot(void) __noreturn;