On Thu, Jan 28, 2021 at 9:59 PM Bernhard Kirchen <[email protected]> wrote: > > "sf protect lock" did only protect against accidental writes by > software. it did not lock down the config or block-protection registers > if the WP# pin was deasserted. hardware write protection was never > enabled for these devices. > > this change implements setting the WPEN bit and clearing the IOC bit in > SST26* devices' config register if any block is protected by "sf protect > lock" command, thus enabling hardware write protection. this behavior is > similar to the "sf protect lock" implementation for Micron (and > compatible) chips. > > Signed-off-by: Bernhard Kirchen <[email protected]> > --- > > drivers/mtd/spi/spi-nor-core.c | 64 ++++++++++++++++++++++++++++++++-- > include/linux/mtd/spi-nor.h | 1 + > 2 files changed, 63 insertions(+), 2 deletions(-) > > diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c > index 050aeac3fa..10c01cf20e 100644 > --- a/drivers/mtd/spi/spi-nor-core.c > +++ b/drivers/mtd/spi/spi-nor-core.c > @@ -185,7 +185,9 @@ static int read_fsr(struct spi_nor *nor) > * location. Return the configuration register value. > * Returns negative if error occurred. > */ > -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) > +#if defined(CONFIG_SPI_FLASH_SPANSION) || \ > + defined(CONFIG_SPI_FLASH_WINBOND) || \ > + defined(CONFIG_SPI_FLASH_SST) > static int read_cr(struct spi_nor *nor) > { > int ret; > @@ -972,6 +974,8 @@ read_err: > #define SST26_MAX_BPR_REG_LEN (18 + 1) > #define SST26_BOUND_REG_SIZE ((32 + SST26_BPR_8K_NUM * 8) * SZ_1K) > > +static int write_cr(struct spi_nor *nor, u8 value); > + > enum lock_ctl { > SST26_CTL_LOCK, > SST26_CTL_UNLOCK, > @@ -994,6 +998,35 @@ static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 > bit, enum lock_ctl ctl) > return false; > } > > +static int sst26_hardware_write_protection(struct spi_nor *nor, bool lock) > +{ > + int ret; > + u8 cr_val; > + > + cr_val = read_cr(nor); > + if (cr_val < 0) { > + dev_err(nor->dev, "fail to read config register value\n"); > + return cr_val; > + } > + > + cr_val &= ~CR_WPEN; > + > + if (lock) { > + // disallow further writes if WP# pin is not asserted. > + cr_val |= CR_WPEN; > + // force quad SPI disabled as otherwise WP# pin works as data > line. > + cr_val &= ~CR_QUAD_EN_SPAN; > + } > + > + ret = write_cr(nor, cr_val); > + if (ret < 0) { > + dev_err(nor->dev, "fail to configure WP# pin (hardware write > protection)\n"); > + return ret; > + } > + > + return 0; > +} > + > /* > * Lock, unlock or check lock status of the flash region of the flash > (depending > * on the lock_ctl value) > @@ -1101,6 +1134,14 @@ static int sst26_lock_ctl(struct spi_nor *nor, loff_t > ofs, uint64_t len, enum lo > return ret; > } > > + // enable hardware write protection iff any protection bit is set > + for (i = 0; i < bpr_size; ++i) > + if (bpr_buff[i] != 0) > + break;
This looks odd to traverse the list to find the protection bit set, better to check the locked range something it was done in stmicro flash chips.

