mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
SPI NOR changes for 6.17
Notable changes: - Fix exiting 4-byte addressing on Infineon SEMPER flashes. These flashes do not support the standard EX4B opcode (E9h), and use a vendor-specific opcode (B8h) instead. - Fix unlocking of flashes that are write-protected at power-on. This was caused by using an uninitialized mtd_info in spi_nor_try_unlock_all(). -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQTlUWNzXGEo3bFmyIR4drqP028CQUCaIIcbAAKCRAR4drqP028 CcnDAQDj6YyRac/AqiKa+W0KL5n0AneymQtb/Pjkme2DaV++cwD/Slfk2ljsO5zN cAhKd6ZKOuu1BhKgHAFg577UNAxs2A8= =mXJz -----END PGP SIGNATURE----- Merge tag 'spi-nor/for-6.17' into mtd/next SPI NOR changes for 6.17 Notable changes: - Fix exiting 4-byte addressing on Infineon SEMPER flashes. These flashes do not support the standard EX4B opcode (E9h), and use a vendor-specific opcode (B8h) instead. - Fix unlocking of flashes that are write-protected at power-on. This was caused by using an uninitialized mtd_info in spi_nor_try_unlock_all(). Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
commit
3dd8aa0ef7
|
|
@ -20,7 +20,7 @@ properties:
|
|||
- pattern: "^((((micron|spansion|st),)?\
|
||||
(m25p(40|80|16|32|64|128)|\
|
||||
n25q(32b|064|128a11|128a13|256a|512a|164k)))|\
|
||||
atmel,at25df(321a|641|081a)|\
|
||||
atmel,at(25|26)df(321a|641|081a)|\
|
||||
everspin,mr25h(10|40|128|256)|\
|
||||
(mxicy|macronix),mx25l(4005a|1606e|6405d|8005|12805d|25635e)|\
|
||||
(mxicy|macronix),mx25u(4033|4035)|\
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ static int mt25qu512a_post_bfpt_fixup(struct spi_nor *nor,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups mt25qu512a_fixups = {
|
||||
static const struct spi_nor_fixups mt25qu512a_fixups = {
|
||||
.post_bfpt = mt25qu512a_post_bfpt_fixup,
|
||||
};
|
||||
|
||||
|
|
@ -225,15 +225,15 @@ static int st_nor_two_die_late_init(struct spi_nor *nor)
|
|||
return spi_nor_set_4byte_addr_mode(nor, true);
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups n25q00_fixups = {
|
||||
static const struct spi_nor_fixups n25q00_fixups = {
|
||||
.late_init = st_nor_four_die_late_init,
|
||||
};
|
||||
|
||||
static struct spi_nor_fixups mt25q01_fixups = {
|
||||
static const struct spi_nor_fixups mt25q01_fixups = {
|
||||
.late_init = st_nor_two_die_late_init,
|
||||
};
|
||||
|
||||
static struct spi_nor_fixups mt25q02_fixups = {
|
||||
static const struct spi_nor_fixups mt25q02_fixups = {
|
||||
.late_init = st_nor_four_die_late_init,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
||||
#define SPINOR_OP_CLPEF 0x82 /* Clear program/erase failure flags */
|
||||
#define SPINOR_OP_CYPRESS_EX4B 0xB8 /* Exit 4-byte address mode */
|
||||
#define SPINOR_OP_CYPRESS_DIE_ERASE 0x61 /* Chip (die) erase */
|
||||
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
|
||||
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
|
||||
|
|
@ -58,6 +59,13 @@
|
|||
SPI_MEM_OP_DUMMY(ndummy, 0), \
|
||||
SPI_MEM_OP_DATA_IN(1, buf, 0))
|
||||
|
||||
#define CYPRESS_NOR_EN4B_EX4B_OP(enable) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(enable ? SPINOR_OP_EN4B : \
|
||||
SPINOR_OP_CYPRESS_EX4B, 0), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPANSION_OP(opcode) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
|
|
@ -356,6 +364,20 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
struct spi_mem_op op = CYPRESS_NOR_EN4B_EX4B_OP(enable);
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
|
||||
* (3 or 4-byte) by querying status
|
||||
|
|
@ -526,6 +548,9 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
struct spi_mem_op op;
|
||||
int ret;
|
||||
|
||||
/* Assign 4-byte address mode method that is not determined in BFPT */
|
||||
nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -578,7 +603,7 @@ static int s25fs256t_late_init(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25fs256t_fixups = {
|
||||
static const struct spi_nor_fixups s25fs256t_fixups = {
|
||||
.post_bfpt = s25fs256t_post_bfpt_fixup,
|
||||
.post_sfdp = s25fs256t_post_sfdp_fixup,
|
||||
.late_init = s25fs256t_late_init,
|
||||
|
|
@ -591,6 +616,9 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
{
|
||||
int ret;
|
||||
|
||||
/* Assign 4-byte address mode method that is not determined in BFPT */
|
||||
nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -650,7 +678,7 @@ static int s25hx_t_late_init(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25hx_t_fixups = {
|
||||
static const struct spi_nor_fixups s25hx_t_fixups = {
|
||||
.post_bfpt = s25hx_t_post_bfpt_fixup,
|
||||
.post_sfdp = s25hx_t_post_sfdp_fixup,
|
||||
.late_init = s25hx_t_late_init,
|
||||
|
|
@ -718,6 +746,9 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
/* Assign 4-byte address mode method that is not determined in BFPT */
|
||||
nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
|
||||
|
||||
return cypress_nor_set_addr_mode_nbytes(nor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
|
|||
static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
|
||||
u64 *len)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u64 min_prot_len;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
|
||||
|
|
@ -77,13 +76,13 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
|
|||
min_prot_len = spi_nor_get_min_prot_length_sr(nor);
|
||||
*len = min_prot_len << (bp - 1);
|
||||
|
||||
if (*len > mtd->size)
|
||||
*len = mtd->size;
|
||||
if (*len > nor->params->size)
|
||||
*len = nor->params->size;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
|
||||
*ofs = 0;
|
||||
else
|
||||
*ofs = mtd->size - *len;
|
||||
*ofs = nor->params->size - *len;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -158,7 +157,6 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
|
|||
*/
|
||||
static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u64 min_prot_len;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
|
|
@ -183,7 +181,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
can_be_bottom = false;
|
||||
|
||||
/* If anything above us is unlocked, we can't use 'top' protection */
|
||||
if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
|
||||
if (!spi_nor_is_locked_sr(nor, ofs + len, nor->params->size - (ofs + len),
|
||||
status_old))
|
||||
can_be_top = false;
|
||||
|
||||
|
|
@ -195,11 +193,11 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
/* lock_len: length of region that should end up locked */
|
||||
if (use_top)
|
||||
lock_len = mtd->size - ofs;
|
||||
lock_len = nor->params->size - ofs;
|
||||
else
|
||||
lock_len = ofs + len;
|
||||
|
||||
if (lock_len == mtd->size) {
|
||||
if (lock_len == nor->params->size) {
|
||||
val = mask;
|
||||
} else {
|
||||
min_prot_len = spi_nor_get_min_prot_length_sr(nor);
|
||||
|
|
@ -248,7 +246,6 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
*/
|
||||
static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u64 min_prot_len;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
|
|
@ -273,7 +270,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
can_be_top = false;
|
||||
|
||||
/* If anything above us is locked, we can't use 'bottom' protection */
|
||||
if (!spi_nor_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
|
||||
if (!spi_nor_is_unlocked_sr(nor, ofs + len, nor->params->size - (ofs + len),
|
||||
status_old))
|
||||
can_be_bottom = false;
|
||||
|
||||
|
|
@ -285,7 +282,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
/* lock_len: length of region that should remain locked */
|
||||
if (use_top)
|
||||
lock_len = mtd->size - (ofs + len);
|
||||
lock_len = nor->params->size - (ofs + len);
|
||||
else
|
||||
lock_len = ofs;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user