Skip to content

Commit 4e53ab0

Browse files
committed
mtd: spi-nor: Set the 4-Byte Address Mode method based on SFDP data
JESD216 SFDP defines in BFPT methods to enter and exit the 4-Byte Address Mode. The flash parameters and settings that are retrieved from SFDP have higher precedence than the static initialized ones, because they should be more accurate and less error prone than those initialized statically. Parse and favor the BFPT-parsed set_4byte_addr_mode methods. Some regressions may be introduced by this patch, because the params->set_4byte_addr_mode method that was set either in spi_nor_init_default_params() or later overwritten in default_init() hooks, are now be overwritten with a different value based on the BFPT data. If that's the case, the fix is to introduce a post_bfpt fixup hook where one should fix the wrong BFPT info. Link: https://lore.kernel.org/r/20230331074606.3559258-7-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
1 parent 3a4d5f4 commit 4e53ab0

6 files changed

Lines changed: 71 additions & 12 deletions

File tree

drivers/mtd/spi-nor/core.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2898,13 +2898,19 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
28982898
*/
28992899
static void spi_nor_late_init_params(struct spi_nor *nor)
29002900
{
2901+
struct spi_nor_flash_parameter *params = nor->params;
2902+
29012903
if (nor->manufacturer && nor->manufacturer->fixups &&
29022904
nor->manufacturer->fixups->late_init)
29032905
nor->manufacturer->fixups->late_init(nor);
29042906

29052907
if (nor->info->fixups && nor->info->fixups->late_init)
29062908
nor->info->fixups->late_init(nor);
29072909

2910+
/* Default method kept for backward compatibility. */
2911+
if (!params->set_4byte_addr_mode)
2912+
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
2913+
29082914
spi_nor_init_flags(nor);
29092915
spi_nor_init_fixup_flags(nor);
29102916

@@ -2973,7 +2979,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
29732979
struct device_node *np = spi_nor_get_flash_node(nor);
29742980

29752981
params->quad_enable = spi_nor_sr2_bit1_quad_enable;
2976-
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
29772982
params->otp.org = &info->otp_org;
29782983

29792984
/* Default to 16-bit Write Status (01h) Command */

drivers/mtd/spi-nor/macronix.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,17 @@ static const struct flash_info macronix_nor_parts[] = {
108108
static void macronix_nor_default_init(struct spi_nor *nor)
109109
{
110110
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
111-
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
111+
}
112+
113+
static void macronix_nor_late_init(struct spi_nor *nor)
114+
{
115+
if (!nor->params->set_4byte_addr_mode)
116+
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
112117
}
113118

114119
static const struct spi_nor_fixups macronix_nor_fixups = {
115120
.default_init = macronix_nor_default_init,
121+
.late_init = macronix_nor_late_init,
116122
};
117123

118124
const struct spi_nor_manufacturer spi_nor_macronix = {

drivers/mtd/spi-nor/micron-st.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,13 +425,17 @@ static void micron_st_nor_default_init(struct spi_nor *nor)
425425
nor->flags |= SNOR_F_HAS_LOCK;
426426
nor->flags &= ~SNOR_F_HAS_16BIT_SR;
427427
nor->params->quad_enable = NULL;
428-
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
429428
}
430429

431430
static void micron_st_nor_late_init(struct spi_nor *nor)
432431
{
432+
struct spi_nor_flash_parameter *params = nor->params;
433+
433434
if (nor->info->mfr_flags & USE_FSR)
434-
nor->params->ready = micron_st_nor_ready;
435+
params->ready = micron_st_nor_ready;
436+
437+
if (!params->set_4byte_addr_mode)
438+
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
435439
}
436440

437441
static const struct spi_nor_fixups micron_st_nor_fixups = {

drivers/mtd/spi-nor/sfdp.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
438438
size_t len;
439439
int i, cmd, err;
440440
u32 addr, val;
441+
u32 dword;
441442
u16 half;
442443
u8 erase_mask;
443444

@@ -607,6 +608,16 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
607608
break;
608609
}
609610

611+
dword = bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_4B_ADDR_MODE_MASK;
612+
if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_BRWR))
613+
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
614+
else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B))
615+
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
616+
else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B))
617+
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
618+
else
619+
dev_dbg(nor->dev, "BFPT: 4-Byte Address Mode method is not recognized or not implemented\n");
620+
610621
/* Soft Reset support. */
611622
if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
612623
nor->flags |= SNOR_F_SOFT_RESET;

drivers/mtd/spi-nor/sfdp.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
/* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */
1717
#define SFDP_DWORD(i) ((i) - 1)
18+
#define SFDP_MASK_CHECK(dword, mask) (((dword) & (mask)) == (mask))
1819

1920
/* Basic Flash Parameter Table */
2021

@@ -89,6 +90,32 @@ struct sfdp_bfpt {
8990
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
9091
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
9192

93+
#define BFPT_DWORD16_EN4B_MASK GENMASK(31, 24)
94+
#define BFPT_DWORD16_EN4B_ALWAYS_4B BIT(30)
95+
#define BFPT_DWORD16_EN4B_4B_OPCODES BIT(29)
96+
#define BFPT_DWORD16_EN4B_16BIT_NV_CR BIT(28)
97+
#define BFPT_DWORD16_EN4B_BRWR BIT(27)
98+
#define BFPT_DWORD16_EN4B_WREAR BIT(26)
99+
#define BFPT_DWORD16_EN4B_WREN_EN4B BIT(25)
100+
#define BFPT_DWORD16_EN4B_EN4B BIT(24)
101+
#define BFPT_DWORD16_EX4B_MASK GENMASK(18, 14)
102+
#define BFPT_DWORD16_EX4B_16BIT_NV_CR BIT(18)
103+
#define BFPT_DWORD16_EX4B_BRWR BIT(17)
104+
#define BFPT_DWORD16_EX4B_WREAR BIT(16)
105+
#define BFPT_DWORD16_EX4B_WREN_EX4B BIT(15)
106+
#define BFPT_DWORD16_EX4B_EX4B BIT(14)
107+
#define BFPT_DWORD16_4B_ADDR_MODE_MASK \
108+
(BFPT_DWORD16_EN4B_MASK | BFPT_DWORD16_EX4B_MASK)
109+
#define BFPT_DWORD16_4B_ADDR_MODE_16BIT_NV_CR \
110+
(BFPT_DWORD16_EN4B_16BIT_NV_CR | BFPT_DWORD16_EX4B_16BIT_NV_CR)
111+
#define BFPT_DWORD16_4B_ADDR_MODE_BRWR \
112+
(BFPT_DWORD16_EN4B_BRWR | BFPT_DWORD16_EX4B_BRWR)
113+
#define BFPT_DWORD16_4B_ADDR_MODE_WREAR \
114+
(BFPT_DWORD16_EN4B_WREAR | BFPT_DWORD16_EX4B_WREAR)
115+
#define BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B \
116+
(BFPT_DWORD16_EN4B_WREN_EN4B | BFPT_DWORD16_EX4B_WREN_EX4B)
117+
#define BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B \
118+
(BFPT_DWORD16_EN4B_EN4B | BFPT_DWORD16_EX4B_EX4B)
92119
#define BFPT_DWORD16_SWRST_EN_RST BIT(12)
93120

94121
#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29)

drivers/mtd/spi-nor/winbond.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,19 +216,25 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = {
216216
.is_locked = spi_nor_otp_is_locked_sr2,
217217
};
218218

219-
static void winbond_nor_default_init(struct spi_nor *nor)
220-
{
221-
nor->params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
222-
}
223-
224219
static void winbond_nor_late_init(struct spi_nor *nor)
225220
{
226-
if (nor->params->otp.org->n_regions)
227-
nor->params->otp.ops = &winbond_nor_otp_ops;
221+
struct spi_nor_flash_parameter *params = nor->params;
222+
223+
if (params->otp.org->n_regions)
224+
params->otp.ops = &winbond_nor_otp_ops;
225+
226+
/*
227+
* Winbond seems to require that the Extended Address Register to be set
228+
* to zero when exiting the 4-Byte Address Mode, at least for W25Q256FV.
229+
* This requirement is not described in the JESD216 SFDP standard, thus
230+
* it is Winbond specific. Since we do not know if other Winbond flashes
231+
* have the same requirement, play safe and overwrite the method parsed
232+
* from BFPT, if any.
233+
*/
234+
params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
228235
}
229236

230237
static const struct spi_nor_fixups winbond_nor_fixups = {
231-
.default_init = winbond_nor_default_init,
232238
.late_init = winbond_nor_late_init,
233239
};
234240

0 commit comments

Comments
 (0)