Message ID | 1445002140-7493-4-git-send-email-festevam@gmail.com |
---|---|
State | Superseded |
Headers | show |
On 16 October 2015 at 18:58, Fabio Estevam <festevam@gmail.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 Build error with DM_SPI_FLASH: CC drivers/mtd/spi/sf_ops.o drivers/mtd/spi/sf_ops.c: In function 'spi_flash_cmd_erase_ops': drivers/mtd/spi/sf_ops.c:280:11: error: 'struct spi_flash' has no member named 'is_locked' drivers/mtd/spi/sf_ops.c: In function 'spi_flash_cmd_write_ops': drivers/mtd/spi/sf_ops.c:327:11: error: 'struct spi_flash' has no member named 'is_locked' make[1]: *** [drivers/mtd/spi/sf_ops.o] Error 1 make: *** [drivers/mtd/spi] Error 2 > > Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com> > --- > Changes since v6: > - Fixed some build issues reported by buildman > > 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 | 27 +++++++++++++++++++++++++++ > include/spi_flash.h | 35 +++++++++++++++++++++++++++++++++++ > 6 files changed, 138 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 > + 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 059cdd3..a0e3759 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..6da9d6c 100644 > --- a/drivers/mtd/spi/sf_probe.c > +++ b/drivers/mtd/spi/sf_probe.c > @@ -149,6 +149,9 @@ 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; > + flash->lock = spi_flash_cmd_lock_ops; > + flash->unlock = spi_flash_cmd_unlock_ops; > + flash->is_locked = spi_flash_cmd_is_locked_ops; > #endif > > /* Compute the flash size */ > @@ -469,6 +472,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 +509,9 @@ 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, > + .lock = spi_flash_std_lock, > + .unlock = spi_flash_std_unlock, > + .is_locked = spi_flash_std_is_locked, > }; > > static const struct udevice_id spi_flash_std_ids[] = { > diff --git a/include/spi_flash.h b/include/spi_flash.h > index 3b2d555..6cc4925 100644 > --- a/include/spi_flash.h > +++ b/include/spi_flash.h > @@ -105,6 +105,9 @@ struct spi_flash { > int (*write)(struct spi_flash *flash, u32 offset, size_t len, > const void *buf); > int (*erase)(struct spi_flash *flash, u32 offset, size_t len); > + 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); > #endif > }; > > @@ -113,6 +116,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 */ > @@ -154,6 +160,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); > @@ -185,6 +205,12 @@ 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) > +{ > + 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, > @@ -227,6 +253,15 @@ 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) > +{ Add something like this- if (!spi_flash->lock) return -EOPNOTSUPP; Same for dm case as well. > + if (prot) > + return flash->lock(flash, ofs, len); > + else > + return flash->unlock(flash, ofs, len); > +} > #endif > > void spi_boot(void) __noreturn; > -- > 1.9.1 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot
On 16 October 2015 at 20:59, Jagan Teki <jteki@openedev.com> wrote: > On 16 October 2015 at 18:58, Fabio Estevam <festevam@gmail.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 > > Build error with DM_SPI_FLASH: > > CC drivers/mtd/spi/sf_ops.o > drivers/mtd/spi/sf_ops.c: In function 'spi_flash_cmd_erase_ops': > drivers/mtd/spi/sf_ops.c:280:11: error: 'struct spi_flash' has no > member named 'is_locked' > drivers/mtd/spi/sf_ops.c: In function 'spi_flash_cmd_write_ops': > drivers/mtd/spi/sf_ops.c:327:11: error: 'struct spi_flash' has no > member named 'is_locked' > make[1]: *** [drivers/mtd/spi/sf_ops.o] Error 1 > make: *** [drivers/mtd/spi] Error 2 > > >> >> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com> >> --- >> Changes since v6: >> - Fixed some build issues reported by buildman >> >> 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 | 27 +++++++++++++++++++++++++++ >> include/spi_flash.h | 35 +++++++++++++++++++++++++++++++++++ >> 6 files changed, 138 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 >> + 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 059cdd3..a0e3759 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..6da9d6c 100644 >> --- a/drivers/mtd/spi/sf_probe.c >> +++ b/drivers/mtd/spi/sf_probe.c >> @@ -149,6 +149,9 @@ 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; Assign these hooks only for STMICRO, do the same for dm-spi-flash as well. >> + flash->lock = spi_flash_cmd_lock_ops; >> + flash->unlock = spi_flash_cmd_unlock_ops; >> + flash->is_locked = spi_flash_cmd_is_locked_ops; >> #endif >> >> /* Compute the flash size */ >> @@ -469,6 +472,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 +509,9 @@ 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, >> + .lock = spi_flash_std_lock, >> + .unlock = spi_flash_std_unlock, >> + .is_locked = spi_flash_std_is_locked, >> }; >> >> static const struct udevice_id spi_flash_std_ids[] = { >> diff --git a/include/spi_flash.h b/include/spi_flash.h >> index 3b2d555..6cc4925 100644 >> --- a/include/spi_flash.h >> +++ b/include/spi_flash.h >> @@ -105,6 +105,9 @@ struct spi_flash { >> int (*write)(struct spi_flash *flash, u32 offset, size_t len, >> const void *buf); >> int (*erase)(struct spi_flash *flash, u32 offset, size_t len); >> + 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); >> #endif >> }; >> >> @@ -113,6 +116,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 */ >> @@ -154,6 +160,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); >> @@ -185,6 +205,12 @@ 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) >> +{ >> + 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, >> @@ -227,6 +253,15 @@ 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) >> +{ > > Add something like this- > > if (!spi_flash->lock) > return -EOPNOTSUPP; > > Same for dm case as well. > >> + if (prot) >> + return flash->lock(flash, ofs, len); >> + else >> + return flash->unlock(flash, ofs, len); >> +} >> #endif >> >> void spi_boot(void) __noreturn; >> -- >> 1.9.1 >> >> _______________________________________________ >> U-Boot mailing list >> U-Boot@lists.denx.de >> http://lists.denx.de/mailman/listinfo/u-boot > > > > -- > Jagan | openedev.
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 059cdd3..a0e3759 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..6da9d6c 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -149,6 +149,9 @@ 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; + flash->lock = spi_flash_cmd_lock_ops; + flash->unlock = spi_flash_cmd_unlock_ops; + flash->is_locked = spi_flash_cmd_is_locked_ops; #endif /* Compute the flash size */ @@ -469,6 +472,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 +509,9 @@ 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, + .lock = spi_flash_std_lock, + .unlock = spi_flash_std_unlock, + .is_locked = spi_flash_std_is_locked, }; static const struct udevice_id spi_flash_std_ids[] = { diff --git a/include/spi_flash.h b/include/spi_flash.h index 3b2d555..6cc4925 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -105,6 +105,9 @@ struct spi_flash { int (*write)(struct spi_flash *flash, u32 offset, size_t len, const void *buf); int (*erase)(struct spi_flash *flash, u32 offset, size_t len); + 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); #endif }; @@ -113,6 +116,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 */ @@ -154,6 +160,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); @@ -185,6 +205,12 @@ 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) +{ + 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, @@ -227,6 +253,15 @@ 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 (prot) + return flash->lock(flash, ofs, len); + else + return flash->unlock(flash, ofs, len); +} #endif void spi_boot(void) __noreturn;