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 read-only. 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 role 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@xxxxxxxxxxx> --- Hi Tudor, 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. Best regards, Jonas 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 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -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; - if (!use_top) status_new |= SR_TB; -- 2.20.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/