mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
mtd: spi-nor: move flags into spi_nor_flash_parameter
Right now the SFDP parsing code is modifying both members of struct spi_nor_flash_parameter and struct spi_nor. This may lead to inconsistencies if the parsing fails because only the flash parameters are rolled back. To fix this, move the flags into the struct spi_nor_flash_parameter. Reported-by: Sashiko <sashiko-bot@kernel.org> Closes: https://sashiko.dev/#/patchset/20260601125438.3481722-1-mwalle%40kernel.org?part=3 Signed-off-by: Michael Walle <mwalle@kernel.org>
This commit is contained in:
parent
e37ee87348
commit
0ede46b4f5
|
|
@ -83,6 +83,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
|
|||
struct spi_mem_op *op,
|
||||
const enum spi_nor_protocol proto)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 ext;
|
||||
|
||||
op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto);
|
||||
|
|
@ -116,7 +117,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
|
|||
op->cmd.nbytes = 2;
|
||||
}
|
||||
|
||||
if (proto == SNOR_PROTO_8_8_8_DTR && nor->flags & SNOR_F_SWAP16)
|
||||
if (proto == SNOR_PROTO_8_8_8_DTR && params->flags & SNOR_F_SWAP16)
|
||||
op->data.swap16 = true;
|
||||
}
|
||||
|
||||
|
|
@ -633,7 +634,7 @@ int spi_nor_sr_ready(struct spi_nor *nor)
|
|||
*/
|
||||
static bool spi_nor_use_parallel_locking(struct spi_nor *nor)
|
||||
{
|
||||
return nor->flags & SNOR_F_RWW;
|
||||
return nor->params->flags & SNOR_F_RWW;
|
||||
}
|
||||
|
||||
/* Locking helpers for status read operations */
|
||||
|
|
@ -860,12 +861,13 @@ static int spi_nor_write_sr1_and_check(struct spi_nor *nor, u8 sr1)
|
|||
*/
|
||||
static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
int ret;
|
||||
u8 *sr_cr = nor->bouncebuf;
|
||||
u8 cr_written;
|
||||
|
||||
/* Make sure we don't overwrite the contents of Status Register 2. */
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR)) {
|
||||
ret = spi_nor_read_cr(nor, &sr_cr[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -906,7 +908,7 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (nor->flags & SNOR_F_NO_READ_CR)
|
||||
if (params->flags & SNOR_F_NO_READ_CR)
|
||||
return 0;
|
||||
|
||||
cr_written = sr_cr[1];
|
||||
|
|
@ -961,7 +963,7 @@ int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (nor->flags & SNOR_F_NO_READ_CR)
|
||||
if (nor->params->flags & SNOR_F_NO_READ_CR)
|
||||
return 0;
|
||||
|
||||
ret = spi_nor_read_cr(nor, &sr_cr[1]);
|
||||
|
|
@ -1009,7 +1011,7 @@ static int spi_nor_write_16bit_sr_cr_and_check(struct spi_nor *nor, const u8 *re
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (nor->flags & SNOR_F_NO_READ_CR)
|
||||
if (nor->params->flags & SNOR_F_NO_READ_CR)
|
||||
return 0;
|
||||
|
||||
ret = spi_nor_read_cr(nor, &nor->bouncebuf[1]);
|
||||
|
|
@ -1035,7 +1037,7 @@ static int spi_nor_write_16bit_sr_cr_and_check(struct spi_nor *nor, const u8 *re
|
|||
*/
|
||||
int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1)
|
||||
{
|
||||
if (nor->flags & SNOR_F_HAS_16BIT_SR)
|
||||
if (nor->params->flags & SNOR_F_HAS_16BIT_SR)
|
||||
return spi_nor_write_16bit_sr_and_check(nor, sr1);
|
||||
|
||||
return spi_nor_write_sr1_and_check(nor, sr1);
|
||||
|
|
@ -1052,7 +1054,7 @@ int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1)
|
|||
*/
|
||||
int spi_nor_write_sr_cr_and_check(struct spi_nor *nor, const u8 *regs)
|
||||
{
|
||||
if (nor->flags & SNOR_F_HAS_16BIT_SR)
|
||||
if (nor->params->flags & SNOR_F_HAS_16BIT_SR)
|
||||
return spi_nor_write_16bit_sr_cr_and_check(nor, regs);
|
||||
|
||||
return spi_nor_write_sr1_and_check(nor, regs[0]);
|
||||
|
|
@ -1821,6 +1823,7 @@ static int spi_nor_erase_dice(struct spi_nor *nor, loff_t addr,
|
|||
static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
struct spi_nor *nor = mtd_to_spi_nor(mtd);
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 n_dice = nor->params->n_dice;
|
||||
bool multi_die_erase = false;
|
||||
u32 addr, len, rem;
|
||||
|
|
@ -1852,7 +1855,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||
return ret;
|
||||
|
||||
/* chip (die) erase? */
|
||||
if ((len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) ||
|
||||
if ((len == mtd->size && !(params->flags & SNOR_F_NO_OP_CHIP_ERASE)) ||
|
||||
multi_die_erase) {
|
||||
ret = spi_nor_erase_dice(nor, addr, len, die_size);
|
||||
if (ret)
|
||||
|
|
@ -1942,7 +1945,7 @@ int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (nor->flags & SNOR_F_NO_READ_CR)
|
||||
if (nor->params->flags & SNOR_F_NO_READ_CR)
|
||||
return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1);
|
||||
|
||||
ret = spi_nor_read_cr(nor, nor->bouncebuf);
|
||||
|
|
@ -2502,7 +2505,7 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps)
|
|||
* If the reset line is broken, we do not want to enter a stateful
|
||||
* mode.
|
||||
*/
|
||||
if (nor->flags & SNOR_F_BROKEN_RESET)
|
||||
if (params->flags & SNOR_F_BROKEN_RESET)
|
||||
*hwcaps &= ~(SNOR_HWCAPS_X_X_X | SNOR_HWCAPS_X_X_X_DTR);
|
||||
|
||||
for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
|
||||
|
|
@ -2526,13 +2529,13 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps)
|
|||
}
|
||||
|
||||
/* Some SPI controllers might not support CR read opcode. */
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR)) {
|
||||
struct spi_mem_op op = SPI_NOR_RDCR_OP(nor->bouncebuf);
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
if (!spi_mem_supports_op(nor->spimem, &op))
|
||||
nor->flags |= SNOR_F_NO_READ_CR;
|
||||
params->flags |= SNOR_F_NO_READ_CR;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2749,6 +2752,8 @@ static int spi_nor_select_erase(struct spi_nor *nor)
|
|||
|
||||
static int spi_nor_set_addr_nbytes(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (nor->params->addr_nbytes) {
|
||||
nor->addr_nbytes = nor->params->addr_nbytes;
|
||||
} else if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) {
|
||||
|
|
@ -2783,8 +2788,8 @@ static int spi_nor_set_addr_nbytes(struct spi_nor *nor)
|
|||
}
|
||||
|
||||
/* Set 4byte opcodes when possible. */
|
||||
if (nor->addr_nbytes == 4 && nor->flags & SNOR_F_4B_OPCODES &&
|
||||
!(nor->flags & SNOR_F_HAS_4BAIT))
|
||||
if (nor->addr_nbytes == 4 && params->flags & SNOR_F_4B_OPCODES &&
|
||||
!(params->flags & SNOR_F_HAS_4BAIT))
|
||||
spi_nor_set_4byte_opcodes(nor);
|
||||
|
||||
return 0;
|
||||
|
|
@ -2947,39 +2952,40 @@ static void spi_nor_no_sfdp_init_params(struct spi_nor *nor)
|
|||
*/
|
||||
static void spi_nor_init_flags(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
struct device_node *np = spi_nor_get_flash_node(nor);
|
||||
const u16 flags = nor->info->flags;
|
||||
|
||||
if (of_property_read_bool(np, "broken-flash-reset"))
|
||||
nor->flags |= SNOR_F_BROKEN_RESET;
|
||||
params->flags |= SNOR_F_BROKEN_RESET;
|
||||
|
||||
if (of_property_read_bool(np, "no-wp"))
|
||||
nor->flags |= SNOR_F_NO_WP;
|
||||
params->flags |= SNOR_F_NO_WP;
|
||||
|
||||
if (flags & SPI_NOR_SWP_IS_VOLATILE)
|
||||
nor->flags |= SNOR_F_SWP_IS_VOLATILE;
|
||||
params->flags |= SNOR_F_SWP_IS_VOLATILE;
|
||||
|
||||
if (flags & SPI_NOR_HAS_LOCK)
|
||||
nor->flags |= SNOR_F_HAS_LOCK;
|
||||
params->flags |= SNOR_F_HAS_LOCK;
|
||||
|
||||
if (flags & SPI_NOR_HAS_TB) {
|
||||
nor->flags |= SNOR_F_HAS_SR_TB;
|
||||
params->flags |= SNOR_F_HAS_SR_TB;
|
||||
if (flags & SPI_NOR_TB_SR_BIT6)
|
||||
nor->flags |= SNOR_F_HAS_SR_TB_BIT6;
|
||||
params->flags |= SNOR_F_HAS_SR_TB_BIT6;
|
||||
}
|
||||
|
||||
if (flags & SPI_NOR_4BIT_BP) {
|
||||
nor->flags |= SNOR_F_HAS_4BIT_BP;
|
||||
params->flags |= SNOR_F_HAS_4BIT_BP;
|
||||
if (flags & SPI_NOR_BP3_SR_BIT6)
|
||||
nor->flags |= SNOR_F_HAS_SR_BP3_BIT6;
|
||||
params->flags |= SNOR_F_HAS_SR_BP3_BIT6;
|
||||
}
|
||||
|
||||
if (flags & SPI_NOR_HAS_CMP)
|
||||
nor->flags |= SNOR_F_HAS_SR2_CMP_BIT6;
|
||||
params->flags |= SNOR_F_HAS_SR2_CMP_BIT6;
|
||||
|
||||
if (flags & SPI_NOR_RWW && nor->params->n_banks > 1 &&
|
||||
!nor->controller_ops)
|
||||
nor->flags |= SNOR_F_RWW;
|
||||
params->flags |= SNOR_F_RWW;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2992,13 +2998,14 @@ static void spi_nor_init_flags(struct spi_nor *nor)
|
|||
*/
|
||||
static void spi_nor_init_fixup_flags(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
const u8 fixup_flags = nor->info->fixup_flags;
|
||||
|
||||
if (fixup_flags & SPI_NOR_4B_OPCODES)
|
||||
nor->flags |= SNOR_F_4B_OPCODES;
|
||||
params->flags |= SNOR_F_4B_OPCODES;
|
||||
|
||||
if (fixup_flags & SPI_NOR_IO_MODE_EN_VOLATILE)
|
||||
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
|
||||
params->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3043,7 +3050,7 @@ static int spi_nor_late_init_params(struct spi_nor *nor)
|
|||
* NOR protection support. When locking_ops are not provided, we pick
|
||||
* the default ones.
|
||||
*/
|
||||
if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops)
|
||||
if (params->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops)
|
||||
spi_nor_init_default_locking_ops(nor);
|
||||
|
||||
if (params->n_banks > 1)
|
||||
|
|
@ -3108,7 +3115,7 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
|
|||
params->otp.org = info->otp;
|
||||
|
||||
/* Default to 16-bit Write Status (01h) Command */
|
||||
nor->flags |= SNOR_F_HAS_16BIT_SR;
|
||||
params->flags |= SNOR_F_HAS_16BIT_SR;
|
||||
|
||||
/* Set SPI NOR sizes. */
|
||||
params->writesize = 1;
|
||||
|
|
@ -3229,7 +3236,7 @@ static int spi_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
|
|||
nor->write_proto == SNOR_PROTO_8_8_8_DTR))
|
||||
return 0;
|
||||
|
||||
if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
|
||||
if (!(nor->params->flags & SNOR_F_IO_MODE_EN_VOLATILE))
|
||||
return 0;
|
||||
|
||||
ret = nor->params->set_octal_dtr(nor, enable);
|
||||
|
|
@ -3282,7 +3289,7 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
|||
* reboots (e.g., crashes). Warn the user (or hopefully, system
|
||||
* designer) that this is bad.
|
||||
*/
|
||||
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
|
||||
WARN_ONCE(nor->params->flags & SNOR_F_BROKEN_RESET,
|
||||
"enabling reset hack; may not recover from unexpected reboots\n");
|
||||
}
|
||||
|
||||
|
|
@ -3303,6 +3310,7 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
|||
|
||||
static int spi_nor_init(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
int err;
|
||||
|
||||
err = spi_nor_set_octal_dtr(nor, true);
|
||||
|
|
@ -3330,13 +3338,13 @@ static int spi_nor_init(struct spi_nor *nor)
|
|||
spi_nor_cache_sr_lock_bits(nor, NULL);
|
||||
if (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE) ||
|
||||
(IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE) &&
|
||||
nor->flags & SNOR_F_SWP_IS_VOLATILE)) {
|
||||
params->flags & SNOR_F_SWP_IS_VOLATILE)) {
|
||||
spi_nor_try_unlock_all(nor);
|
||||
}
|
||||
|
||||
if (nor->addr_nbytes == 4 &&
|
||||
nor->read_proto != SNOR_PROTO_8_8_8_DTR &&
|
||||
!(nor->flags & SNOR_F_4B_OPCODES))
|
||||
!(params->flags & SNOR_F_4B_OPCODES))
|
||||
return spi_nor_set_4byte_addr_mode(nor, true);
|
||||
|
||||
return 0;
|
||||
|
|
@ -3451,11 +3459,12 @@ static void spi_nor_put_device(struct mtd_info *mtd)
|
|||
|
||||
static void spi_nor_restore(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
int ret;
|
||||
|
||||
/* restore the addressing mode */
|
||||
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
|
||||
nor->flags & SNOR_F_BROKEN_RESET) {
|
||||
if (nor->addr_nbytes == 4 && !(params->flags & SNOR_F_4B_OPCODES) &&
|
||||
params->flags & SNOR_F_BROKEN_RESET) {
|
||||
ret = spi_nor_set_4byte_addr_mode(nor, false);
|
||||
if (ret)
|
||||
/*
|
||||
|
|
@ -3466,7 +3475,7 @@ static void spi_nor_restore(struct spi_nor *nor)
|
|||
dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret);
|
||||
}
|
||||
|
||||
if (nor->flags & SNOR_F_SOFT_RESET)
|
||||
if (params->flags & SNOR_F_SOFT_RESET)
|
||||
spi_nor_soft_reset(nor);
|
||||
}
|
||||
|
||||
|
|
@ -3583,7 +3592,7 @@ static int spi_nor_set_mtd_info(struct spi_nor *nor)
|
|||
mtd->type = MTD_NORFLASH;
|
||||
mtd->flags = MTD_CAP_NORFLASH;
|
||||
/* Unset BIT_WRITEABLE to enable JFFS2 write buffer for ECC'd NOR */
|
||||
if (nor->flags & SNOR_F_ECC)
|
||||
if (nor->params->flags & SNOR_F_ECC)
|
||||
mtd->flags &= ~MTD_BIT_WRITEABLE;
|
||||
if (nor->info->flags & SPI_NOR_NO_ERASE)
|
||||
mtd->flags |= MTD_NO_ERASE;
|
||||
|
|
|
|||
|
|
@ -348,6 +348,7 @@ struct spi_nor_otp {
|
|||
*
|
||||
* @bank_size: the flash memory bank density in bytes.
|
||||
* @size: the total flash memory density in bytes.
|
||||
* @flags: flag options for the current SPI NOR (SNOR_F_*)
|
||||
* @writesize Minimal writable flash unit size. Defaults to 1. Set to
|
||||
* ECC unit size for ECC-ed flashes.
|
||||
* @page_size: the page size of the SPI NOR flash memory.
|
||||
|
|
@ -386,6 +387,7 @@ struct spi_nor_otp {
|
|||
struct spi_nor_flash_parameter {
|
||||
u64 bank_size;
|
||||
u64 size;
|
||||
u32 flags;
|
||||
u32 writesize;
|
||||
u32 page_size;
|
||||
u8 addr_nbytes;
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
|
|||
seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes);
|
||||
|
||||
seq_puts(s, "flags\t\t");
|
||||
spi_nor_print_flags(s, nor->flags, snor_f_names,
|
||||
spi_nor_print_flags(s, params->flags, snor_f_names,
|
||||
ARRAY_SIZE(snor_f_names));
|
||||
seq_puts(s, "\n");
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
|
||||
if (!(params->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
|
||||
string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
|
||||
seq_printf(s, " %02x (%s)\n", params->die_erase_opcode, buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
|
|||
* its BFPT table.
|
||||
*/
|
||||
if (bfpt->dwords[SFDP_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4)
|
||||
nor->flags |= SNOR_F_4B_OPCODES;
|
||||
nor->params->flags |= SNOR_F_4B_OPCODES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ static int mt25qu512a_post_bfpt_fixup(struct spi_nor *nor,
|
|||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
nor->params->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -632,8 +632,8 @@ static int micron_st_nor_ready(struct spi_nor *nor)
|
|||
|
||||
static void micron_st_nor_default_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->flags |= SNOR_F_HAS_LOCK;
|
||||
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
nor->params->flags |= SNOR_F_HAS_LOCK;
|
||||
nor->params->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
nor->params->quad_enable = NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -577,17 +577,17 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
|
|||
* Read Configuration Register (35h) instruction is not
|
||||
* supported.
|
||||
*/
|
||||
nor->flags |= SNOR_F_HAS_16BIT_SR | SNOR_F_NO_READ_CR;
|
||||
params->flags |= SNOR_F_HAS_16BIT_SR | SNOR_F_NO_READ_CR;
|
||||
params->quad_enable = spi_nor_sr2_bit1_quad_enable;
|
||||
break;
|
||||
|
||||
case BFPT_DWORD15_QER_SR1_BIT6:
|
||||
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
params->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
params->quad_enable = spi_nor_sr1_bit6_quad_enable;
|
||||
break;
|
||||
|
||||
case BFPT_DWORD15_QER_SR2_BIT7:
|
||||
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
params->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
params->quad_enable = spi_nor_sr2_bit7_quad_enable;
|
||||
break;
|
||||
|
||||
|
|
@ -598,7 +598,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
|
|||
* Register 2, so let's be cautious and keep the default
|
||||
* assumption of a 16-bit Write Status (01h) command.
|
||||
*/
|
||||
nor->flags |= SNOR_F_HAS_16BIT_SR;
|
||||
params->flags |= SNOR_F_HAS_16BIT_SR;
|
||||
|
||||
params->quad_enable = spi_nor_sr2_bit1_quad_enable;
|
||||
break;
|
||||
|
|
@ -620,7 +620,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
|
|||
|
||||
/* Soft Reset support. */
|
||||
if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
|
||||
nor->flags |= SNOR_F_SOFT_RESET;
|
||||
params->flags |= SNOR_F_SOFT_RESET;
|
||||
|
||||
/* Stop here if not JESD216 rev C or later. */
|
||||
if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B)
|
||||
|
|
@ -673,7 +673,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
|
|||
|
||||
/* Byte order in 8D-8D-8D mode */
|
||||
if (bfpt.dwords[SFDP_DWORD(18)] & BFPT_DWORD18_BYTE_ORDER_SWAPPED)
|
||||
nor->flags |= SNOR_F_SWAP16;
|
||||
params->flags |= SNOR_F_SWAP16;
|
||||
|
||||
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt);
|
||||
}
|
||||
|
|
@ -1160,7 +1160,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
|
|||
* SFDP compliant memories.
|
||||
*/
|
||||
params->addr_nbytes = 4;
|
||||
nor->flags |= SNOR_F_4B_OPCODES | SNOR_F_HAS_4BAIT;
|
||||
params->flags |= SNOR_F_4B_OPCODES | SNOR_F_HAS_4BAIT;
|
||||
|
||||
/* fall through */
|
||||
out:
|
||||
|
|
@ -1306,7 +1306,7 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
|
|||
|
||||
if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE,
|
||||
dwords[SFDP_DWORD(22)]))
|
||||
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
|
||||
params->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
|
||||
|
||||
out:
|
||||
kfree(dwords);
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ static void cypress_nor_ecc_init(struct spi_nor *nor)
|
|||
* same ECC data unit without an erase are not allowed.
|
||||
*/
|
||||
nor->params->writesize = 16;
|
||||
nor->flags |= SNOR_F_ECC;
|
||||
nor->params->flags |= SNOR_F_ECC;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1139,7 +1139,7 @@ static int spansion_nor_late_init(struct spi_nor *nor)
|
|||
u8 mfr_flags = nor->info->mfr_flags;
|
||||
|
||||
if (params->size > SZ_16M) {
|
||||
nor->flags |= SNOR_F_4B_OPCODES;
|
||||
params->flags |= SNOR_F_4B_OPCODES;
|
||||
/* No small sector erase for 4-byte command set */
|
||||
nor->erase_opcode = SPINOR_OP_SE;
|
||||
nor->mtd.erasesize = nor->info->sector_size ?:
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@
|
|||
|
||||
static u8 spi_nor_get_sr_bp_mask(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6)
|
||||
if (params->flags & SNOR_F_HAS_SR_BP3_BIT6)
|
||||
return mask | SR_BP3_BIT6;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_4BIT_BP)
|
||||
if (params->flags & SNOR_F_HAS_4BIT_BP)
|
||||
return mask | SR_BP3;
|
||||
|
||||
return mask;
|
||||
|
|
@ -26,9 +27,11 @@ static u8 spi_nor_get_sr_bp_mask(struct spi_nor *nor)
|
|||
|
||||
static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (params->flags & SNOR_F_HAS_SR_TB_BIT6)
|
||||
return SR_TB_BIT6;
|
||||
else if (nor->flags & SNOR_F_HAS_SR_TB)
|
||||
else if (params->flags & SNOR_F_HAS_SR_TB)
|
||||
return SR_TB_BIT5;
|
||||
else
|
||||
return 0;
|
||||
|
|
@ -36,8 +39,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor)
|
|||
|
||||
static u8 spi_nor_get_sr_cmp_mask(struct spi_nor *nor)
|
||||
{
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR) &&
|
||||
nor->flags & SNOR_F_HAS_SR2_CMP_BIT6)
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR) &&
|
||||
params->flags & SNOR_F_HAS_SR2_CMP_BIT6)
|
||||
return SR2_CMP_BIT6;
|
||||
else
|
||||
return 0;
|
||||
|
|
@ -67,15 +72,16 @@ u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
|
|||
void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs,
|
||||
u64 *len)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u64 min_prot_len;
|
||||
u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
|
||||
u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
|
||||
u8 cmp_mask = spi_nor_get_sr_cmp_mask(nor);
|
||||
u8 bp, val = sr[0] & bp_mask;
|
||||
bool tb = (nor->flags & SNOR_F_HAS_SR_TB) ? sr[0] & tb_mask : 0;
|
||||
bool tb = (params->flags & SNOR_F_HAS_SR_TB) ? sr[0] & tb_mask : 0;
|
||||
bool cmp = sr[1] & cmp_mask;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)
|
||||
if (params->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)
|
||||
val = (val & ~SR_BP3_BIT6) | SR_BP3;
|
||||
|
||||
bp = val >> SR_BP_SHIFT;
|
||||
|
|
@ -153,10 +159,11 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
|
|||
|
||||
static int spi_nor_sr_set_bp_mask(struct spi_nor *nor, u8 *sr, u8 pow)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
u8 val = pow << SR_BP_SHIFT;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
|
||||
if (params->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
|
||||
val = (val & ~SR_BP3) | SR_BP3_BIT6;
|
||||
|
||||
if (val & ~mask)
|
||||
|
|
@ -200,6 +207,7 @@ static int spi_nor_build_sr(struct spi_nor *nor, const u8 *old_sr, u8 *new_sr,
|
|||
*/
|
||||
void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
|
||||
u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
|
||||
u8 cmp_mask = spi_nor_get_sr_cmp_mask(nor);
|
||||
|
|
@ -212,7 +220,7 @@ void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr)
|
|||
|
||||
sr_cr[0] = nor->bouncebuf[0];
|
||||
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (spi_nor_read_cr(nor, nor->bouncebuf))
|
||||
return;
|
||||
}
|
||||
|
|
@ -261,13 +269,14 @@ void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr)
|
|||
*/
|
||||
static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
|
||||
u8 status_old[2] = {}, status_new[2] = {}, status_new_cmp[2] = {};
|
||||
u8 *best_status_new = status_new;
|
||||
loff_t ofs_old, ofs_new, ofs_new_cmp;
|
||||
u64 len_old, len_new, len_new_cmp;
|
||||
loff_t lock_len;
|
||||
bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB,
|
||||
bool can_be_top = true, can_be_bottom = params->flags & SNOR_F_HAS_SR_TB,
|
||||
can_be_cmp = spi_nor_get_sr_cmp_mask(nor);
|
||||
bool use_top;
|
||||
int ret;
|
||||
|
|
@ -279,7 +288,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
status_old[0] = nor->bouncebuf[0];
|
||||
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR)) {
|
||||
ret = spi_nor_read_cr(nor, nor->bouncebuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -313,7 +322,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
lock_len = ofs + len;
|
||||
|
||||
if (lock_len == nor->params->size)
|
||||
pow = (nor->flags & SNOR_F_HAS_4BIT_BP) ? GENMASK(3, 0) : GENMASK(2, 0);
|
||||
pow = (params->flags & SNOR_F_HAS_4BIT_BP) ? GENMASK(3, 0) : GENMASK(2, 0);
|
||||
else
|
||||
pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;
|
||||
|
||||
|
|
@ -359,7 +368,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
* wrongly tied to GND (that includes internal pull-downs).
|
||||
* WP# pin hard strapped to GND can be a valid use case.
|
||||
*/
|
||||
if (!(nor->flags & SNOR_F_NO_WP))
|
||||
if (!(params->flags & SNOR_F_NO_WP))
|
||||
best_status_new[0] |= SR_SRWD;
|
||||
|
||||
spi_nor_get_locked_range_sr(nor, status_old, &ofs_old, &len_old);
|
||||
|
|
@ -378,7 +387,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
(ofs_old < ofs_new || (ofs_new + len_new) < (ofs_old + len_old)))
|
||||
return -EINVAL;
|
||||
|
||||
if (nor->flags & SNOR_F_NO_READ_CR)
|
||||
if (params->flags & SNOR_F_NO_READ_CR)
|
||||
ret = spi_nor_write_sr_and_check(nor, best_status_new[0]);
|
||||
else
|
||||
ret = spi_nor_write_sr_cr_and_check(nor, best_status_new);
|
||||
|
|
@ -397,13 +406,14 @@ 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 spi_nor_flash_parameter *params = nor->params;
|
||||
u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
|
||||
u8 status_old[2] = {}, status_new[2] = {}, status_new_cmp[2] = {};
|
||||
u8 *best_status_new = status_new;
|
||||
loff_t ofs_old, ofs_new, ofs_new_cmp;
|
||||
u64 len_old, len_new, len_new_cmp;
|
||||
loff_t lock_len;
|
||||
bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB,
|
||||
bool can_be_top = true, can_be_bottom = params->flags & SNOR_F_HAS_SR_TB,
|
||||
can_be_cmp = spi_nor_get_sr_cmp_mask(nor);
|
||||
bool use_top;
|
||||
int ret;
|
||||
|
|
@ -415,7 +425,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
status_old[0] = nor->bouncebuf[0];
|
||||
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR)) {
|
||||
ret = spi_nor_read_cr(nor, nor->bouncebuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -512,7 +522,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
(ofs_new < ofs_old || (ofs_old + len_old) < (ofs_new + len_new)))
|
||||
return -EINVAL;
|
||||
|
||||
if (nor->flags & SNOR_F_NO_READ_CR)
|
||||
if (params->flags & SNOR_F_NO_READ_CR)
|
||||
ret = spi_nor_write_sr_and_check(nor, best_status_new[0]);
|
||||
else
|
||||
ret = spi_nor_write_sr_cr_and_check(nor, best_status_new);
|
||||
|
|
@ -533,6 +543,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
*/
|
||||
static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, u64 len)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 sr_cr[2] = {};
|
||||
int ret;
|
||||
|
||||
|
|
@ -542,7 +553,7 @@ static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
sr_cr[0] = nor->bouncebuf[0];
|
||||
|
||||
if (!(nor->flags & SNOR_F_NO_READ_CR)) {
|
||||
if (!(params->flags & SNOR_F_NO_READ_CR)) {
|
||||
ret = spi_nor_read_cr(nor, nor->bouncebuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -628,9 +639,10 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, u64 len)
|
|||
*/
|
||||
void spi_nor_try_unlock_all(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
int ret;
|
||||
|
||||
if (!(nor->flags & SNOR_F_HAS_LOCK))
|
||||
if (!(params->flags & SNOR_F_HAS_LOCK))
|
||||
return;
|
||||
|
||||
dev_dbg(nor->dev, "Unprotecting entire flash array\n");
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ w25q256_post_bfpt_fixups(struct spi_nor *nor,
|
|||
*/
|
||||
if (bfpt_header->major == SFDP_JESD216_MAJOR &&
|
||||
bfpt_header->minor == SFDP_JESD216A_MINOR)
|
||||
nor->flags |= SNOR_F_4B_OPCODES;
|
||||
nor->params->flags |= SNOR_F_4B_OPCODES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ winbond_rdcr_post_bfpt_fixup(struct spi_nor *nor,
|
|||
* both incorrect and impractical, as the chip features a CMP bit for its
|
||||
* locking scheme that lays in the Control Register, and needs to be read.
|
||||
*/
|
||||
nor->flags &= ~SNOR_F_NO_READ_CR;
|
||||
nor->params->flags &= ~SNOR_F_NO_READ_CR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -365,7 +365,6 @@ struct spi_nor_flash_parameter;
|
|||
* @read_dummy: the dummy needed by the read operation
|
||||
* @program_opcode: the program opcode
|
||||
* @sst_write_second: used by the SST write operation
|
||||
* @flags: flag options for the current SPI NOR (SNOR_F_*)
|
||||
* @read_proto: the SPI protocol for read operations
|
||||
* @write_proto: the SPI protocol for write operations
|
||||
* @reg_proto: the SPI protocol for read_reg/write_reg/erase operations
|
||||
|
|
@ -406,7 +405,6 @@ struct spi_nor {
|
|||
enum spi_nor_protocol write_proto;
|
||||
enum spi_nor_protocol reg_proto;
|
||||
bool sst_write_second;
|
||||
u32 flags;
|
||||
struct sfdp *sfdp;
|
||||
struct dentry *debugfs_root;
|
||||
u8 dfs_sr_cache[2];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user