[PATCH v3 1/1] spi-nor: always respect write-protect input
jonas at norrbonn.se
Fri Apr 26 23:23:13 PDT 2019
The status register bit SRWD (status register write disable) is
described in many words in the datasheets but effectively boils down to:
i) if set, respect WP# when trying to change protection bits;
ii) if unset, ignore WP# when trying to change protection bits
In short, the bit determines whether the WP# signal is honored or not.
This protection bit is used in a couple of different ways:
i) Some designs attach WP# directly to ground. At first boot, they
write to the NOR and call flash_lock; this results in the BP0-2 block
protection bits and SRWD being set. As WP# is permanently grounded,
this block protection cannot be undone and the NOR is effectively
ii) Some designs can control WP#, thus allowing the protection of the
SRWD bit itself to be managed. When the hardware pulls WP# low, SRWD
and the BP[0-2] block protection bits cannot be changed; when hardware
sets WP# high, the block protection bits can be freely changed,
_irregardless_ of the state of SRWD.
iii) In the third configuration WP# is pulled high internally, thereby
rendering the SRWD bit ineffective. In this configuration, the BP[0-2]
block protection bits can always be freely modified; this puts the
writability of the NOR flash exclusively under software control.
Linux currently sets SRWD when flash_lock is invoked. This prevents
further modification of the BP[0-2] bits and the SRWD bit itself, _if_
WP# is in play; if WP# is not in play, this setting has no effect. This
behaviour is rational.
Linux, however, clears SRWD when the flash_unlock is invoked to clear
all BP[0-2] bits. If WP# is low, this will fail and SRWD and the block
protection bits will remain unchanged. If WP# is high, changing the
BP[0-2] bits will succeed irregardless of the state of SRWD, so clearing
SRWD has no meaningful effect here.
There is, however, another scenario where clearing SRWD when calling
flash_unlock causes unwanted behaviour. If the BPNV bit is set, the
BP[0-2] bits revert to "fully protected" at reset. In this
configuration, only someone who can control WP# is able to call
flash_unlock and clear the block protection bits. In this
configuration, it is desirable that SRWD is not ever cleared so that the
WP# always has full control over the writability of the BP[0-2] bits.
This allows the NOR flash to be made writable _only_ by someone who has
control over the WP# signal; for others, the NOR is read-only.
Given the above, this patch removes the clearing of the SRWD bit from
the flash_unlock path. With this, Linux only ever sets the SRWD; it
will never clear it. This should be compatible with all three
configuration outlined above:
i) If WP# is permanently grounded, SRWD is not clearable anyway.
ii) If WP# is controllable, SRWD is moot because WP# takes over its
iii) If WP# is floating and thereby pulled permanently high, SRWD has
no effect on the writability of the block protection bits.
Tested on a Cypress s25fl512s.
Signed-off-by: Jonas Bonn <jonas at norrbonn.se>
I think this problem is simpler than we think. Just removing the clear
of SRWD in the flash_unlock path is sufficient to cover all the various
cases, as far as I can tell.
drivers/mtd/spi-nor/spi-nor.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index fae147452aff..bc3317f2bc7c 100644
@@ -1313,10 +1313,6 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
status_new = (status_old & ~mask & ~SR_TB) | val;
- /* Don't protect status register if we're fully unlocked */
- if (lock_len == 0)
- status_new &= ~SR_SRWD;
status_new |= SR_TB;
More information about the linux-mtd