[U-Boot] [U-BOOT PATCH 2/3] spi: nor: add support for is25wp256

Bin Meng bmeng.cn at gmail.com
Mon Aug 26 10:02:26 UTC 2019


On Wed, Aug 14, 2019 at 1:23 AM Sagar Shrikant Kadam
<sagar.kadam at sifive.com> wrote:
>
> Enable support for spi nor device(is25wp256) mounted on
> HiFive Unleashed Rev A00 board.
>
> Thanks to Bhargav Shah for porting this patch which is based on
> linux patches https://lkml.org/lkml/2019/7/2/859.
>
> Additionally, set the proper number of sectors in the device id table,
> so that the sf probe shows the correct size of the flash device.
> Added SPI_NOR_HAS_BP3 bit to indicate that this nor device has BP3 bit
> present for the lock/unlock mechanism.
> Registered a post bfpt fixup handler for this device as the address width
> advertised by the flash during nor scan is not correct.
>
> This flash is tested for plain SPI mode although it also supports QUAD
> I/O mode.
>
> Signed-off-by: Bhargav Shah <bhargavshah1988 at gmail.com>
> Signed-off-by: Sagar Shrikant Kadam <sagar.kadam at sifive.com>
> ---
>  board/sifive/fu540/Kconfig     |   5 +
>  drivers/mtd/spi/sf_internal.h  |  18 +++
>  drivers/mtd/spi/spi-nor-core.c | 340 +++++++++++++++++++++++++++++++++++------
>  drivers/mtd/spi/spi-nor-ids.c  |   5 +
>  include/linux/mtd/spi-nor.h    |   8 +
>  5 files changed, 326 insertions(+), 50 deletions(-)
>
> diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
> index 5d65080..f9d5ec1 100644
> --- a/board/sifive/fu540/Kconfig
> +++ b/board/sifive/fu540/Kconfig
> @@ -40,6 +40,11 @@ config BOARD_SPECIFIC_OPTIONS # dummy
>         imply SIFIVE_SERIAL
>         imply SPI
>         imply SPI_SIFIVE
> +       imply SPI_FLASH
> +       imply SPI_FLASH_ISSI
> +       imply SPI_FLASH_SFDP_SUPPORT
> +       imply CMD_MTD
> +       imply CMD_SF
>         imply MMC
>         imply MMC_SPI
>         imply MMC_BROKEN_CD

This should be a separate patch.

> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index c5e68d8..6523107 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -65,6 +65,13 @@ struct flash_info {
>  #define NO_CHIP_ERASE          BIT(12) /* Chip does not support chip erase */
>  #define SPI_NOR_SKIP_SFDP      BIT(13) /* Skip parsing of SFDP tables */
>  #define USE_CLSR               BIT(14) /* use CLSR command */
> +#define SPI_NOR_HAS_BP3                BIT(15) /*
> +                                        * Flash SR has block protect bits
> +                                        * for lock/unlock purpose, few support
> +                                        * BP0-BP2 while few support BP0-BP3.
> +                                        * This flag identifies devices that
> +                                        * support BP3 bit.
> +                                        */
>
>  #ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
>         /* Part specific fixup hooks */
> @@ -72,6 +79,17 @@ struct flash_info {
>  #endif
>  };
>
> +#ifdef CONFIG_SPI_FLASH_SFDP_SUPPORT
> +/*
> + * Declare manufacturer specific fixup handlers that
> + * can be registered as fixup's in flash info table
> + * so as to update any wrong/broken SFDP parameter.
> + */
> +#ifdef CONFIG_SPI_FLASH_ISSI
> +extern struct spi_nor_fixups is25wp256_fixups;
> +#endif
> +#endif
> +
>  extern const struct flash_info spi_nor_ids[];
>
>  #define JEDEC_MFR(info)        ((info)->id[0])
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index 4306d19..46d278d 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -582,7 +582,8 @@ erase_err:
>         return ret;
>  }
>
> -#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
> +#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) || \
> +       defined(CONFIG_SPI_FLASH_ISSI)
>  /* Write status register and ensure bits in mask match written values */
>  static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
>  {
> @@ -604,14 +605,45 @@ static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
>         return ((ret & mask) != (status_new & mask)) ? -EIO : 0;
>  }
>
> +/**
> + * spi_nor_read_fr() -read function register
> + * @nor: pointer to a 'struct spi_nor'.
> + *
> + * ISSI devices have top/bottom area protection bits selection into function
> + * reg. The bits in FR are OTP. So once it's written, it cannot be changed.
> + *
> + * Return: Value in function register or negative if error.
> + */
> +static int spi_nor_read_fr(struct spi_nor *nor)
> +{
> +       int ret;
> +       u8 val;
> +
> +       ret = nor->read_reg(nor, SPINOR_OP_RDFR, &val, 1);
> +       if (ret < 0) {
> +               pr_err("error %d reading FR\n", ret);
> +               return ret;
> +       }
> +
> +       return val;
> +}
> +
>  static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
>                                  uint64_t *len)
>  {
>         struct mtd_info *mtd = &nor->mtd;
> -       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
> -       int shift = ffs(mask) - 1;
> +       u8 mask = 0;
> +       u8 fr = 0;
> +       int shift = 0;
>         int pow;
>
> +       if (nor->flags & SNOR_F_HAS_BP3)
> +               mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
> +       else
> +               mask = SR_BP2 | SR_BP1 | SR_BP0;
> +
> +       shift = ffs(mask) - 1;
> +
>         if (!(sr & mask)) {
>                 /* No protection */
>                 *ofs = 0;
> @@ -619,10 +651,20 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
>         } else {
>                 pow = ((sr & mask) ^ mask) >> shift;
>                 *len = mtd->size >> pow;
> -               if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
> -                       *ofs = 0;
> -               else
> -                       *ofs = mtd->size - *len;
> +
> +               /* ISSI device's have top/bottom select bit in func reg */
> +               if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) {
> +                       fr = spi_nor_read_fr(nor);
> +                       if (nor->flags & SNOR_F_HAS_SR_TB && fr & FR_TB)
> +                               *ofs = 0;
> +                       else
> +                               *ofs = mtd->size - *len;
> +               } else {
> +                       if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
> +                               *ofs = 0;
> +                       else
> +                               *ofs = mtd->size - *len;
> +               }
>         }
>  }
>
> @@ -649,18 +691,109 @@ static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, u64 len,
>                 return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
>  }
>
> -static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> -                           u8 sr)
> +/*
> + * check if memory region is locked
> + *
> + * Returns false if region is locked 0 otherwise.
> + */
> +static int spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> +                               u8 sr)
>  {
>         return stm_check_lock_status_sr(nor, ofs, len, sr, true);
>  }
>
> -static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> -                             u8 sr)
> +/*
> + * check if memory region is unlocked
> + *
> + * Returns false if region is locked 0 otherwise.
> + */
> +static int spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
> +                                 u8 sr)
>  {
>         return stm_check_lock_status_sr(nor, ofs, len, sr, false);
>  }
>
> +/**
> + * spi_nor_select_zone() - Select top area or bottom area to lock/unlock
> + * @nor: pointer to a 'struct spi_nor'.
> + * @ofs: offset from which to lock memory.
> + * @len: number of bytes to unlock.
> + * @sr: status register
> + * @tb: pointer to top/bottom bool used in caller function
> + * @op: zone selection is for lock/unlock operation. 1: lock 0:unlock
> + *
> + * Select the top area / bottom area pattern to protect memory blocks.
> + *
> + * Returns negative on errors, 0 on success.
> + */
> +static int spi_nor_select_zone(struct spi_nor *nor, loff_t ofs, uint64_t len,
> +                              u8 sr, bool *tb, bool op)
> +{
> +       int retval;
> +       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
> +
> +       if (op) {
> +               /* Select for lock zone operation */
> +
> +               /*
> +                * If nothing in our range is unlocked, we don't need
> +                * to do anything.
> +                */
> +               if (spi_nor_is_locked_sr(nor, ofs, len, sr))
> +                       return 0;
> +
> +               /*
> +                * If anything below us is unlocked, we can't use 'bottom'
> +                * protection.
> +                */
> +               if (!spi_nor_is_locked_sr(nor, 0, ofs, sr))
> +                       can_be_bottom = false;
> +
> +               /*
> +                * If anything above us is unlocked, we can't use 'top'
> +                * protection.
> +                */
> +               if (!spi_nor_is_locked_sr(nor, ofs + len,
> +                                         nor->mtd.size - (ofs + len), sr))
> +                       can_be_top = false;
> +       } else {
> +               /* Select unlock zone */
> +
> +               /*
> +                * If nothing in our range is locked, we don't need to
> +                * do anything.
> +                */
> +               if (spi_nor_is_unlocked_sr(nor, ofs, len, sr))
> +                       return 0;
> +
> +               /*
> +                * If anything below us is locked, we can't use 'top'
> +                * protection
> +                */
> +               if (!spi_nor_is_unlocked_sr(nor, 0, ofs, sr))
> +                       can_be_top = false;
> +
> +               /*
> +                * If anything above us is locked, we can't use 'bottom'
> +                * protection
> +                */
> +               if (!spi_nor_is_unlocked_sr(nor, ofs + len,
> +                                           nor->mtd.size - (ofs + len), sr))
> +                       can_be_bottom = false;
> +       }
> +
> +       if (!can_be_bottom && !can_be_top) {
> +               retval = -EINVAL;
> +       } else {
> +               /* Prefer top, if both are valid */
> +               *tb = can_be_top;
> +               retval = 1;
> +       }
> +
> +       return retval;
> +}
> +
> +#if !defined(CONFIG_SPI_FLASH_ISSI)
>  /*
>   * Lock a region of the flash. Compatible with ST Micro and similar flash.
>   * Supports the block protection bits BP{0,1,2} in the status register
> @@ -698,33 +831,19 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
>         struct mtd_info *mtd = &nor->mtd;
>         int status_old, status_new;
>         u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
> -       u8 shift = ffs(mask) - 1, pow, val;
> +       u8 shift = ffs(mask) - 1, pow, val, ret;
>         loff_t lock_len;
> -       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
>         bool use_top;
>
>         status_old = read_sr(nor);
>         if (status_old < 0)
>                 return status_old;
>
> -       /* If nothing in our range is unlocked, we don't need to do anything */
> -       if (stm_is_locked_sr(nor, ofs, len, status_old))
> +       ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 1);
> +       if (!ret)
>                 return 0;
> -
> -       /* If anything below us is unlocked, we can't use 'bottom' protection */
> -       if (!stm_is_locked_sr(nor, 0, ofs, status_old))
> -               can_be_bottom = false;
> -
> -       /* If anything above us is unlocked, we can't use 'top' protection */
> -       if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
> -                             status_old))
> -               can_be_top = false;
> -
> -       if (!can_be_bottom && !can_be_top)
> -               return -EINVAL;
> -
> -       /* Prefer top, if both are valid */
> -       use_top = can_be_top;
> +       else if (ret < 0)
> +               return ret;
>
>         /* lock_len: length of region that should end up locked */
>         if (use_top)
> @@ -778,33 +897,19 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
>         struct mtd_info *mtd = &nor->mtd;
>         int status_old, status_new;
>         u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
> -       u8 shift = ffs(mask) - 1, pow, val;
> +       u8 shift = ffs(mask) - 1, pow, val, ret;
>         loff_t lock_len;
> -       bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
>         bool use_top;
>
>         status_old = read_sr(nor);
>         if (status_old < 0)
>                 return status_old;
>
> -       /* If nothing in our range is locked, we don't need to do anything */
> -       if (stm_is_unlocked_sr(nor, ofs, len, status_old))
> +       ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 0);
> +       if (!ret)
>                 return 0;
> -
> -       /* If anything below us is locked, we can't use 'top' protection */
> -       if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
> -               can_be_top = false;
> -
> -       /* If anything above us is locked, we can't use 'bottom' protection */
> -       if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
> -                               status_old))
> -               can_be_bottom = false;
> -
> -       if (!can_be_bottom && !can_be_top)
> -               return -EINVAL;
> -
> -       /* Prefer top, if both are valid */
> -       use_top = can_be_top;
> +       else if (ret < 0)
> +               return ret;
>
>         /* lock_len: length of region that should remain locked */
>         if (use_top)
> @@ -866,8 +971,9 @@ static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
>         if (status < 0)
>                 return status;
>
> -       return stm_is_locked_sr(nor, ofs, len, status);
> +       return spi_nor_is_locked_sr(nor, ofs, len, status);
>  }
> +#endif /* !CONFIG_SPI_FLASH_ISSI*/
>  #endif /* CONFIG_SPI_FLASH_STMICRO */
>
>  static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
> @@ -1142,6 +1248,105 @@ static int macronix_quad_enable(struct spi_nor *nor)
>  }
>  #endif
>
> +/**
> + * issi_lock() - set BP[0123] write-protection.
> + * @nor: pointer to a 'struct spi_nor'.
> + * @ofs: offset from which to lock memory.
> + * @len: number of bytes to unlock.
> + *
> + * Lock a region of the flash.Implementation is based on stm_lock
> + * Supports the block protection bits BP{0,1,2,3} in status register
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int issi_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
> +{
> +       int status_old, status_new, blk_prot;
> +       u8 mask = SR_BP3 | SR_BP2 | SR_BP1 | SR_BP0;
> +       u8 shift = ffs(mask) - 1;
> +       u8 pow, ret;
> +       bool use_top = false;
> +       loff_t lock_len;
> +
> +       status_old = read_sr(nor);
> +
> +       /* if status reg is Write protected don't update bit protection */
> +       if (status_old & SR_SRWD) {
> +               dev_err(nor->dev,
> +                       "SR is write protected, can't update BP bits...\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = spi_nor_select_zone(nor, ofs, len, status_old, &use_top, 1);
> +       if (!ret)
> +               /* Older protected blocks include the new requested block's */
> +               return 0;
> +       else if (ret < 0)
> +               return ret;
> +
> +       /* lock_len: length of region that should end up locked */
> +       if (use_top)
> +               lock_len = nor->mtd.size - ofs;
> +       else
> +               lock_len = ofs + len;
> +
> +       pow = order_base_2(lock_len);
> +       blk_prot = mask & (((pow + 1) & 0xf) << shift);
> +       if (lock_len <= 0) {
> +               dev_err(nor->dev, "invalid Length to protect");
> +               return -EINVAL;
> +       }
> +
> +       status_new = status_old | blk_prot;
> +       if (status_old == status_new)
> +               return 0;
> +
> +       return write_sr_and_check(nor, status_new, mask);
> +}
> +
> +/**
> + * issi_unlock() - clear BP[0123] write-protection.
> + * @nor: pointer to a 'struct spi_nor'.
> + * @ofs: offset from which to unlock memory.
> + * @len: number of bytes to unlock.
> + *
> + * Bits [2345] of the Status Register are BP[0123].
> + * ISSI chips use a different block protection scheme than other chips.
> + * Just disable the write-protect unilaterally.
> + *
> + * Return: 0 on success, -errno otherwise.
> + */
> +static int issi_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
> +{
> +       int ret, val;
> +       u8 mask = SR_BP0 | SR_BP1 | SR_BP2 | SR_BP3;
> +
> +       val = read_sr(nor);
> +       if (val < 0)
> +               return val;
> +       if (!(val & mask))
> +               return 0;
> +
> +       write_enable(nor);
> +
> +       write_sr(nor, val & ~mask);
> +
> +       ret = spi_nor_wait_till_ready(nor);
> +       if (ret)
> +               return ret;
> +
> +       ret = read_sr(nor);
> +       if (!(ret & mask)) {
> +               dev_info(nor->dev, "ISSI block protect bits cleared SR: 0x%x\n",
> +                        ret);
> +               ret = 0;
> +       } else {
> +               dev_err(nor->dev, "ISSI block protect bits not cleared\n");
> +               ret = -EINVAL;
> +       }
> +       return ret;
> +}
> +
>  #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
>  /*
>   * Write status Register and configuration register with 2 bytes
> @@ -1649,6 +1854,28 @@ spi_nor_post_bfpt_fixups(struct spi_nor *nor,
>         return 0;
>  }
>
> +static int is25wp256_post_bfpt_fixups(struct spi_nor *nor,
> +                                     const struct sfdp_parameter_header
> +                                               *bfpt_header,
> +                                     const struct sfdp_bfpt *bfpt,
> +                                     struct spi_nor_flash_parameter *params)
> +
> +{
> +       /* IS25WP256 supports 4B opcodes, but the BFPT advertises a
> +        * BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width.
> +        * Overwrite the address width advertised by the BFPT.
> +        */
> +       if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
> +                       BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
> +               nor->addr_width = 4;
> +
> +       return 0;
> +}
> +
> +struct spi_nor_fixups is25wp256_fixups = {
> +       .post_bfpt = is25wp256_post_bfpt_fixups,
> +};
> +
>  /**
>   * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
>   * @nor:               pointer to a 'struct spi_nor'
> @@ -2318,6 +2545,16 @@ int spi_nor_scan(struct spi_nor *nor)
>         mtd->_erase = spi_nor_erase;
>         mtd->_read = spi_nor_read;
>
> +#if defined(CONFIG_SPI_FLASH_ISSI)
> +       /* NOR protection support for ISSI chips */
> +       if (JEDEC_MFR(info) == SNOR_MFR_ISSI &&
> +           info->flags & SPI_NOR_HAS_LOCK &&
> +           info->flags & SPI_NOR_HAS_BP3) {
> +               nor->flash_lock = issi_lock;
> +               nor->flash_unlock = issi_unlock;
> +       }
> +#endif
> +
>  #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
>         /* NOR protection support for STmicro/Micron chips and similar */
>         if (JEDEC_MFR(info) == SNOR_MFR_ST ||
> @@ -2347,6 +2584,8 @@ int spi_nor_scan(struct spi_nor *nor)
>         if (info->flags & USE_CLSR)
>                 nor->flags |= SNOR_F_USE_CLSR;
>
> +       if (info->flags & SPI_NOR_HAS_BP3)
> +               nor->flags |= SNOR_F_HAS_BP3;
>         if (info->flags & SPI_NOR_NO_ERASE)
>                 mtd->flags |= MTD_NO_ERASE;
>
> @@ -2377,6 +2616,7 @@ int spi_nor_scan(struct spi_nor *nor)
>                 /* enable 4-byte addressing if the device exceeds 16MiB */
>                 nor->addr_width = 4;
>                 if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
> +                   JEDEC_MFR(info) == SNOR_MFR_ISSI ||
>                     info->flags & SPI_NOR_4B_OPCODES)
>                         spi_nor_set_4byte_opcodes(nor, info);
>  #else
> diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
> index a3920ba..0d97aa9 100644
> --- a/drivers/mtd/spi/spi-nor-ids.c
> +++ b/drivers/mtd/spi/spi-nor-ids.c
> @@ -128,6 +128,11 @@ const struct flash_info spi_nor_ids[] = {
>                         SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
>         { INFO("is25wp128",  0x9d7018, 0, 64 * 1024, 256,
>                         SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> +       { INFO("is25wp256", 0x9d7019, 0, 64 * 1024, 512,
> +                       SECT_4K | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK |
> +                       SPI_NOR_HAS_TB | SPI_NOR_HAS_BP3)
> +                       .fixups = &is25wp256_fixups

Updating spi-nor-ids.c should be a separate patch following the
spi-nor core changes.

> +       },
>  #endif
>  #ifdef CONFIG_SPI_FLASH_MACRONIX       /* MACRONIX */
>         /* Macronix */
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index 88e80af..2fe7812 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -26,6 +26,7 @@
>  #define SNOR_MFR_SPANSION      CFI_MFR_AMD
>  #define SNOR_MFR_SST           CFI_MFR_SST
>  #define SNOR_MFR_WINBOND       0xef /* Also used by some Spansion */
> +#define SNOR_MFR_ISSI          0x9d
>
>  /*
>   * Note on opcode nomenclature: some opcodes have a format like
> @@ -39,6 +40,8 @@
>  #define SPINOR_OP_WREN         0x06    /* Write enable */
>  #define SPINOR_OP_RDSR         0x05    /* Read status register */
>  #define SPINOR_OP_WRSR         0x01    /* Write status register 1 byte */
> +#define SPINOR_OP_RDFR         0x48    /* Read Function register */
> +#define SPINOR_OP_WRFR         0x42    /* Write Function register 1 byte */
>  #define SPINOR_OP_RDSR2                0x3f    /* Read status register 2 */
>  #define SPINOR_OP_WRSR2                0x3e    /* Write status register 2 */
>  #define SPINOR_OP_READ         0x03    /* Read data bytes (low frequency) */
> @@ -119,6 +122,7 @@
>  #define SR_BP0                 BIT(2)  /* Block protect 0 */
>  #define SR_BP1                 BIT(3)  /* Block protect 1 */
>  #define SR_BP2                 BIT(4)  /* Block protect 2 */
> +#define SR_BP3                 BIT(5)  /* Block protect 3 */
>  #define SR_TB                  BIT(5)  /* Top/Bottom protect */
>  #define SR_SRWD                        BIT(7)  /* SR write protect */
>  /* Spansion/Cypress specific status bits */
> @@ -130,6 +134,9 @@
>  /* Enhanced Volatile Configuration Register bits */
>  #define EVCR_QUAD_EN_MICRON    BIT(7)  /* Micron Quad I/O */
>
> +/* Function register bit */
> +#define FR_TB                  BIT(1)  /*ISSI: Top/Bottom protect */
> +
>  /* Flag Status Register bits */
>  #define FSR_READY              BIT(7)  /* Device status, 0 = Busy, 1 = Ready */
>  #define FSR_E_ERR              BIT(5)  /* Erase operation status */
> @@ -234,6 +241,7 @@ enum spi_nor_option_flags {
>         SNOR_F_READY_XSR_RDY    = BIT(4),
>         SNOR_F_USE_CLSR         = BIT(5),
>         SNOR_F_BROKEN_RESET     = BIT(6),
> +       SNOR_F_HAS_BP3          = BIT(7),
>  };
>
>  /**

Regards,
Bin


More information about the U-Boot mailing list