[U-Boot] [PATCH v6 16/16] sf: Add SPI NOR protection mechanism

Jagan Teki jteki at openedev.com
Tue Nov 3 17:23:29 CET 2015


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 at openedev.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
>
> Signed-off-by: Fabio Estevam <fabio.estevam at freescale.com>
> [re-worked to fit the lock common to dm and non-dm]
> Signed-off-by: Jagan Teki <jteki at openedev.com>
> Reviewed-by: Tom Rini <trini at konsulko.com>
> Reviewed-by: Heiko Schocher <hs at denx.de>
> Reviewed-by: Jagan Teki <jteki at 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
>



-- 
Jagan | openedev.


More information about the U-Boot mailing list