[U-Boot] [PATCH v7 4/4] spi: Add SPI NOR protection mechanism
Jagan Teki
jteki at openedev.com
Fri Oct 16 17:36:20 CEST 2015
On 16 October 2015 at 20:59, Jagan Teki <jteki at openedev.com> wrote:
> On 16 October 2015 at 18:58, Fabio Estevam <festevam at gmail.com> wrote:
>> From: Fabio Estevam <fabio.estevam at 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 at 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 at 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 at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot
>
>
>
> --
> Jagan | openedev.
--
Jagan | openedev.
More information about the U-Boot
mailing list