mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
mtd: spi-nor: Support TB selection using SR bit 6
There are some flashes to use bit 6 of status register for Top/Bottom (TB). Use top/bottom bit variable instead of fixed value and support this case. Set the Top/Bottom (TB) mask based on SPI_NOR_TB_SR_BIT6 flash_info flag. We can't use a bigger granularity, for example to set TB_BIT6 per manufacturer using a SNOR_F flag. The manufacturers don't have a common rule in regards to the TB bit: Winbond : Use the 6th bit from 32MB capacity W25Q20EW, W25Q50BW, W25Q128V - TB(5) W25Q256JV, W25M512JV - TB(6) GigaDevice : Use the 6th bit from 32MB capacity GD25Q16C, GD25Q32C, GD25LQ32D, GD25Q64C, GD25Q128 - TB(5) GD25Q256 - TB(6) Micron/STM : Keep to use 5th bit M25PX64, N25Q128A, N25Q512A, MT25QL512ABB, MT25QL02GCBB - TB(5) Spansion : Use the 6th bit from 16MB capacity S25FL116K, S25FL132K, S25FL165K - TB(5) S25FL128L, S25FL256L - TB(6) We can't make a correlation between TB and BP3 either, i.e. assume that if BP3 is defined then TB will be at BIT(6). Micron breaks this rule. Signed-off-by: Jungseung Lee <js07.lee@samsung.com> [tudor.ambarus@microchip.com: describe the reason for setting a new flash_info flag.] Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
This commit is contained in:
parent
52487e2168
commit
adf1092fa8
2 changed files with 28 additions and 7 deletions
|
@ -196,7 +196,7 @@ struct flash_info {
|
|||
u16 page_size;
|
||||
u16 addr_width;
|
||||
|
||||
u16 flags;
|
||||
u32 flags;
|
||||
#define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */
|
||||
#define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */
|
||||
#define SST_WRITE BIT(2) /* use SST byte programming */
|
||||
|
@ -233,6 +233,11 @@ struct flash_info {
|
|||
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
|
||||
#define USE_CLSR BIT(14) /* use CLSR command */
|
||||
#define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
|
||||
#define SPI_NOR_TB_SR_BIT6 BIT(16) /*
|
||||
* Top/Bottom (TB) is bit 6 of
|
||||
* status register. Must be used with
|
||||
* SPI_NOR_HAS_TB.
|
||||
*/
|
||||
|
||||
/* Part specific fixup hooks. */
|
||||
const struct spi_nor_fixups *fixups;
|
||||
|
@ -1761,9 +1766,13 @@ 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 tb_mask = SR_TB_BIT5;
|
||||
int shift = ffs(mask) - 1;
|
||||
int pow;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
tb_mask = SR_TB_BIT6;
|
||||
|
||||
if (!(sr & mask)) {
|
||||
/* No protection */
|
||||
*ofs = 0;
|
||||
|
@ -1771,7 +1780,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 & tb_mask)
|
||||
*ofs = 0;
|
||||
else
|
||||
*ofs = mtd->size - *len;
|
||||
|
@ -1850,6 +1859,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
|||
struct mtd_info *mtd = &nor->mtd;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
|
||||
u8 tb_mask = 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;
|
||||
|
@ -1886,6 +1896,9 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
|||
else
|
||||
lock_len = ofs + len;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
tb_mask = SR_TB_BIT6;
|
||||
|
||||
/*
|
||||
* Need smallest pow such that:
|
||||
*
|
||||
|
@ -1903,13 +1916,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 & ~tb_mask) | val;
|
||||
|
||||
/* Disallow further writes if WP pin is asserted */
|
||||
status_new |= SR_SRWD;
|
||||
|
||||
if (!use_top)
|
||||
status_new |= SR_TB_BIT5;
|
||||
status_new |= tb_mask;
|
||||
|
||||
/* Don't bother if they're the same */
|
||||
if (status_new == status_old)
|
||||
|
@ -1932,6 +1945,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
|||
struct mtd_info *mtd = &nor->mtd;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
|
||||
u8 tb_mask = 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;
|
||||
|
@ -1968,6 +1982,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
|||
else
|
||||
lock_len = ofs;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
tb_mask = SR_TB_BIT6;
|
||||
/*
|
||||
* Need largest pow such that:
|
||||
*
|
||||
|
@ -1987,14 +2003,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 & ~tb_mask) | 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 |= tb_mask;
|
||||
|
||||
/* Don't bother if they're the same */
|
||||
if (status_new == status_old)
|
||||
|
@ -5144,8 +5160,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
|
|||
|
||||
if (info->flags & USE_FSR)
|
||||
nor->flags |= SNOR_F_USE_FSR;
|
||||
if (info->flags & SPI_NOR_HAS_TB)
|
||||
if (info->flags & SPI_NOR_HAS_TB) {
|
||||
nor->flags |= SNOR_F_HAS_SR_TB;
|
||||
if (info->flags & SPI_NOR_TB_SR_BIT6)
|
||||
nor->flags |= SNOR_F_HAS_SR_TB_BIT6;
|
||||
}
|
||||
|
||||
if (info->flags & NO_CHIP_ERASE)
|
||||
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
|
||||
if (info->flags & USE_CLSR)
|
||||
|
|
|
@ -245,6 +245,7 @@ enum spi_nor_option_flags {
|
|||
SNOR_F_HAS_LOCK = BIT(8),
|
||||
SNOR_F_HAS_16BIT_SR = BIT(9),
|
||||
SNOR_F_NO_READ_CR = BIT(10),
|
||||
SNOR_F_HAS_SR_TB_BIT6 = BIT(11),
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue