For winbond and gigadevice flashes, wrong bit for top/bottom selection are being used. Fix it to use appropriate value. Signed-off-by: Jungseung Lee <js07.lee@xxxxxxxxxxx> --- v5: - remake patch based on latest spi-nor/next tree drivers/mtd/spi-nor/spi-nor.c | 24 +++++++++++++++++++----- include/linux/mtd/spi-nor.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 587f23480e5d..5bed03e61bd0 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1411,9 +1411,14 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, { struct mtd_info *mtd = &nor->mtd; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + u8 mask_tb = SR_TB_BIT5; int shift = ffs(mask) - 1; int pow; + if (JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND || + JEDEC_MFR(nor->info) == SNOR_MFR_GIGADEVICE) + mask_tb = SR_TB_BIT6; + if (!(sr & mask)) { /* No protection */ *ofs = 0; @@ -1421,7 +1426,7 @@ 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_BIT5) + if (nor->flags & SNOR_F_HAS_SR_TB && sr & mask_tb) *ofs = 0; else *ofs = mtd->size - *len; @@ -1500,6 +1505,7 @@ 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 mask_tb = SR_TB_BIT5; u8 shift = ffs(mask) - 1, pow, val; loff_t lock_len; bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; @@ -1534,6 +1540,10 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) else lock_len = ofs + len; + if (JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND || + JEDEC_MFR(nor->info) == SNOR_MFR_GIGADEVICE) + mask_tb = SR_TB_BIT6; + /* * Need smallest pow such that: * @@ -1551,13 +1561,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) if (!(val & mask)) return -EINVAL; - status_new = (status_old & ~mask & ~SR_TB_BIT5) | val; + status_new = (status_old & ~mask & ~mask_tb) | val; /* Disallow further writes if WP pin is asserted */ status_new |= SR_SRWD; if (!use_top) - status_new |= SR_TB_BIT5; + status_new |= mask_tb; /* Don't bother if they're the same */ if (status_new == status_old) @@ -1580,6 +1590,7 @@ 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 mask_tb = SR_TB_BIT5; u8 shift = ffs(mask) - 1, pow, val; loff_t lock_len; bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; @@ -1614,6 +1625,9 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) else lock_len = ofs; + if (JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND || + JEDEC_MFR(nor->info) == SNOR_MFR_GIGADEVICE) + mask_tb = SR_TB_BIT6; /* * Need largest pow such that: * @@ -1633,14 +1647,14 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) return -EINVAL; } - status_new = (status_old & ~mask & ~SR_TB_BIT5) | val; + status_new = (status_old & ~mask & ~mask_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_BIT5; + status_new |= mask_tb; /* Don't bother if they're the same */ if (status_new == status_old) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 66c891f0d328..654992a829bd 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -128,6 +128,7 @@ #define SR_BP1 BIT(3) /* Block protect 1 */ #define SR_BP2 BIT(4) /* Block protect 2 */ #define SR_TB_BIT5 BIT(5) /* Top/Bottom protect */ +#define SR_TB_BIT6 BIT(6) /* Top/Bottom protect (on Winbond/GigaDevice) */ #define SR_SRWD BIT(7) /* SR write protect */ /* Spansion/Cypress specific status bits */ #define SR_E_ERR BIT(5) -- 2.17.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/