diff options
Diffstat (limited to 'drivers/mtd/spi/spi-nor-core.c')
-rw-r--r-- | drivers/mtd/spi/spi-nor-core.c | 92 |
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; |