aboutsummaryrefslogtreecommitdiff
path: root/drivers/mtd/spi/spi-nor-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi/spi-nor-core.c')
-rw-r--r--drivers/mtd/spi/spi-nor-core.c92
1 files changed, 56 insertions, 36 deletions
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index c73636d7d1..78de3c5281 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -161,6 +161,7 @@ struct sfdp_header {
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
#define BFPT_DWORD16_SOFT_RST BIT(12)
+#define BFPT_DWORD16_EX4B_PWRCYC BIT(21)
#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29)
#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */
@@ -329,10 +330,10 @@ static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy,
u8 *val)
{
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDAR, 1),
- SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
- SPI_MEM_OP_DUMMY(dummy / 8, 1),
- SPI_MEM_OP_DATA_IN(1, NULL, 1));
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDAR, 1),
+ SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1),
+ SPI_MEM_OP_DUMMY(dummy / 8, 1),
+ SPI_MEM_OP_DATA_IN(1, NULL, 1));
return spi_nor_read_write_reg(nor, &op, val);
}
@@ -340,10 +341,10 @@ static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy,
static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val)
{
struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1),
- SPI_MEM_OP_ADDR(nor->addr_width, addr, 1),
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(1, NULL, 1));
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1),
+ SPI_MEM_OP_ADDR(nor->addr_mode_nbytes, addr, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, NULL, 1));
return spi_nor_read_write_reg(nor, &op, &val);
}
@@ -2236,11 +2237,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
/* Number of address bytes. */
switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY:
+ case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4:
nor->addr_width = 3;
+ nor->addr_mode_nbytes = 3;
break;
case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY:
nor->addr_width = 4;
+ nor->addr_mode_nbytes = 4;
break;
default:
@@ -2516,7 +2520,7 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
for (i = 0; i < sccr_header->length; i++)
table[i] = le32_to_cpu(table[i]);
- if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[22]))
+ if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[21]))
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
out:
@@ -3273,10 +3277,24 @@ static int s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
nor->erase_opcode = SPINOR_OP_SE_4B;
nor->mtd.erasesize = nor->info->sector_size;
- ret = set_4byte(nor, nor->info, 1);
- if (ret)
- return ret;
- nor->addr_width = 4;
+ /*
+ * The default address mode in multi-die package parts (>1Gb) may be
+ * 3- or 4-byte, depending on model number. BootROM code in some SoCs
+ * use 3-byte mode for backward compatibility and should switch to
+ * 4-byte mode after BootROM phase. Since registers in the 2nd die are
+ * mapped within 32-bit address space, we need to make sure the flash is
+ * in 4-byte address mode. The default address mode can be distinguished
+ * by BFPT 16th DWORD. Power cycle exits 4-byte address mode if default
+ * is 3-byte address mode.
+ */
+ if (params->size > SZ_128M) {
+ if (bfpt->dwords[BFPT_DWORD(16)] & BFPT_DWORD16_EX4B_PWRCYC) {
+ ret = set_4byte(nor, nor->info, 1);
+ if (ret)
+ return ret;
+ }
+ nor->addr_mode_nbytes = 4;
+ }
/*
* The page_size is set to 512B from BFPT, but it actually depends on
@@ -3333,7 +3351,7 @@ static struct spi_nor_fixups s25fl256l_fixups = {
};
#endif
-#ifdef CONFIG_SPI_FLASH_S28HS512T
+#ifdef CONFIG_SPI_FLASH_S28HX_T
/**
* spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
* @nor: pointer to a 'struct spi_nor'
@@ -3392,15 +3410,15 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor)
return 0;
}
-static int s28hs512t_erase_non_uniform(struct spi_nor *nor, loff_t addr)
+static int s28hx_t_erase_non_uniform(struct spi_nor *nor, loff_t addr)
{
/* Factory default configuration: 32 x 4 KiB sectors at bottom. */
return spansion_erase_non_uniform(nor, addr, SPINOR_OP_S28_SE_4K,
0, SZ_128K);
}
-static int s28hs512t_setup(struct spi_nor *nor, const struct flash_info *info,
- const struct spi_nor_flash_parameter *params)
+static int s28hx_t_setup(struct spi_nor *nor, const struct flash_info *info,
+ const struct spi_nor_flash_parameter *params)
{
struct spi_mem_op op;
u8 buf;
@@ -3427,19 +3445,19 @@ static int s28hs512t_setup(struct spi_nor *nor, const struct flash_info *info,
return ret;
if (!(buf & SPINOR_REG_CYPRESS_CFR3V_UNISECT))
- nor->erase = s28hs512t_erase_non_uniform;
+ nor->erase = s28hx_t_erase_non_uniform;
return spi_nor_default_setup(nor, info, params);
}
-static void s28hs512t_default_init(struct spi_nor *nor)
+static void s28hx_t_default_init(struct spi_nor *nor)
{
nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable;
- nor->setup = s28hs512t_setup;
+ nor->setup = s28hx_t_setup;
}
-static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor,
- struct spi_nor_flash_parameter *params)
+static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
/*
* On older versions of the flash the xSPI Profile 1.0 table has the
@@ -3469,10 +3487,10 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor,
params->rdsr_addr_nbytes = 4;
}
-static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
- const struct sfdp_parameter_header *bfpt_header,
- const struct sfdp_bfpt *bfpt,
- struct spi_nor_flash_parameter *params)
+static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt,
+ struct spi_nor_flash_parameter *params)
{
struct spi_mem_op op;
u8 buf;
@@ -3509,12 +3527,12 @@ static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
return 0;
}
-static struct spi_nor_fixups s28hs512t_fixups = {
- .default_init = s28hs512t_default_init,
- .post_sfdp = s28hs512t_post_sfdp_fixup,
- .post_bfpt = s28hs512t_post_bfpt_fixup,
+static struct spi_nor_fixups s28hx_t_fixups = {
+ .default_init = s28hx_t_default_init,
+ .post_sfdp = s28hx_t_post_sfdp_fixup,
+ .post_bfpt = s28hx_t_post_bfpt_fixup,
};
-#endif /* CONFIG_SPI_FLASH_S28HS512T */
+#endif /* CONFIG_SPI_FLASH_S28HX_T */
#ifdef CONFIG_SPI_FLASH_MT35XU
static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
@@ -3835,6 +3853,13 @@ void spi_nor_set_fixups(struct spi_nor *nor)
nor->fixups = &s25hx_t_fixups;
break;
+#ifdef CONFIG_SPI_FLASH_S28HX_T
+ case 0x5a: /* S28HL (Octal, 3.3V) */
+ case 0x5b: /* S28HS (Octal, 1.8V) */
+ nor->fixups = &s28hx_t_fixups;
+ break;
+#endif
+
default:
break;
}
@@ -3845,11 +3870,6 @@ void spi_nor_set_fixups(struct spi_nor *nor)
nor->fixups = &s25fl256l_fixups;
#endif
-#ifdef CONFIG_SPI_FLASH_S28HS512T
- if (!strcmp(nor->info->name, "s28hs512t"))
- nor->fixups = &s28hs512t_fixups;
-#endif
-
#ifdef CONFIG_SPI_FLASH_MT35XU
if (!strcmp(nor->info->name, "mt35xu512aba"))
nor->fixups = &mt35xu512aba_fixups;