--- linux-4.9.37/drivers/mtd/spi-nor/spi-nor.c 2017-07-12 16:42:41.000000000 +0300 +++ linux-4.9.y/drivers/mtd/spi-nor/spi-nor.c 2021-06-07 13:01:33.000000000 +0300 @@ -75,6 +75,13 @@ * bit. Must be used with * SPI_NOR_HAS_LOCK. */ +#define SPI_NOR_4B_OPCODES BIT(10) /* + * Use dedicated 4byte address op codes + * to support memory size above 128Mib. + */ + + const struct spi_nor_basic_flash_parameter *params; + u32 clkrate; }; #define JEDEC_MFR(info) ((info)->id[0]) @@ -139,31 +146,24 @@ } /* - * Dummy Cycle calculation for different type of read. - * It can be used to support more commands with - * different dummy cycle requirements. + * Write status register 1 byte + * Returns negative if error occurred. */ -static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor) +static inline int write_sr(struct spi_nor *nor, u8 val) { - switch (nor->flash_read) { - case SPI_NOR_FAST: - case SPI_NOR_DUAL: - case SPI_NOR_QUAD: - return 8; - case SPI_NOR_NORMAL: - return 0; - } - return 0; + nor->cmd_buf[0] = val; + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); } + /* - * Write status register 1 byte + * Write status register-2 1 byte * Returns negative if error occurred. */ -static inline int write_sr(struct spi_nor *nor, u8 val) +static inline int write_sr2(struct spi_nor *nor, u8 val) { nor->cmd_buf[0] = val; - return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); + return nor->write_reg(nor, SPINOR_OP_WRSR2, nor->cmd_buf, 1); } /* @@ -188,9 +188,83 @@ return mtd->priv; } +struct spi_nor_address_entry { + u8 src_opcode; + u8 dst_opcode; +}; + +static u8 spi_nor_convert_opcode(u8 opcode, + const struct spi_nor_address_entry *entries, + size_t num_entries) +{ + unsigned int min, max; + + min = 0; + max = num_entries - 1; + while (min <= max) { + int mid = (min + max) >> 1; + const struct spi_nor_address_entry *entry = &entries[mid]; + + if (opcode == entry->src_opcode) + return entry->dst_opcode; + + if (opcode < entry->src_opcode) + max = mid - 1; + else + min = mid + 1; + } + + /* No conversion found */ + return opcode; +} + +static u8 spi_nor_3to4_opcode(u8 opcode) +{ + /* MUST be sorted by 3byte opcode */ +#define ENTRY_3TO4(_opcode) { _opcode, _opcode##_4B } + static const struct spi_nor_address_entry spi_nor_3to4_table[] = { + ENTRY_3TO4(SPINOR_OP_PP), /* 0x02 */ + ENTRY_3TO4(SPINOR_OP_READ), /* 0x03 */ + ENTRY_3TO4(SPINOR_OP_READ_FAST), /* 0x0b */ + ENTRY_3TO4(SPINOR_OP_BE_4K), /* 0x20 */ + ENTRY_3TO4(SPINOR_OP_PP_1_1_4), /* 0x32 */ + ENTRY_3TO4(SPINOR_OP_PP_1_4_4), /* 0x38 */ + ENTRY_3TO4(SPINOR_OP_READ_1_1_2), /* 0x3b */ + ENTRY_3TO4(SPINOR_OP_BE_32K), /* 0x52 */ + ENTRY_3TO4(SPINOR_OP_READ_1_1_4), /* 0x6b */ + ENTRY_3TO4(SPINOR_OP_READ_1_2_2), /* 0xbb */ + ENTRY_3TO4(SPINOR_OP_SE), /* 0xd8 */ + ENTRY_3TO4(SPINOR_OP_READ_1_4_4), /* 0xeb */ + }; +#undef ENTRY_3TO4 + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_table, + ARRAY_SIZE(spi_nor_3to4_table)); +} + +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, + const struct flash_info *info) +{ + /* Do some manufacturer fixups first */ + switch (JEDEC_MFR(info)) { + case SNOR_MFR_SPANSION: + /* No small sector erase for 4-byte command set */ + nor->erase_opcode = SPINOR_OP_SE; + nor->mtd.erasesize = info->sector_size; + break; + + default: + break; + } + + nor->read_opcode = spi_nor_3to4_opcode(nor->read_opcode); + nor->program_opcode = spi_nor_3to4_opcode(nor->program_opcode); + nor->erase_opcode = spi_nor_3to4_opcode(nor->erase_opcode); +} + /* Enable/disable 4-byte addressing mode. */ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, - int enable) + u32 enable) { int status; bool need_wren = false; @@ -201,16 +275,26 @@ /* Some Micron need WREN command; all will accept it */ need_wren = true; case SNOR_MFR_MACRONIX: - case SNOR_MFR_WINBOND: if (need_wren) write_enable(nor); cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; status = nor->write_reg(nor, cmd, NULL, 0); + if (need_wren) write_disable(nor); return status; + case SNOR_MFR_WINBOND: + if (enable) + return nor->write_reg(nor, SPINOR_OP_EN4B, NULL, 0); + else { + /* w25q256fvfg must send reset to disable 4 byte mode */ + nor->write_reg(nor, SPINOR_ENABLE_RESET, NULL, 0); + nor->write_reg(nor, SPINOR_OP_RESET, NULL, 0); + udelay(30); + } + return 0; default: /* Spansion style */ nor->cmd_buf[0] = enable << 7; @@ -220,24 +304,28 @@ static inline int spi_nor_sr_ready(struct spi_nor *nor) { int sr = read_sr(nor); + if (sr < 0) return sr; else - return !(sr & SR_WIP); + return !((unsigned int)sr & SR_WIP); } -static inline int spi_nor_fsr_ready(struct spi_nor *nor) +static inline unsigned int spi_nor_fsr_ready(struct spi_nor *nor) { int fsr = read_fsr(nor); + unsigned int ufsr = (unsigned int)fsr; + if (fsr < 0) return fsr; else - return fsr & FSR_READY; + return ufsr & FSR_READY; } static int spi_nor_ready(struct spi_nor *nor) { int sr, fsr; + sr = spi_nor_sr_ready(nor); if (sr < 0) return sr; @@ -282,7 +370,31 @@ return spi_nor_wait_till_ready_with_timeout(nor, DEFAULT_READY_WAIT_JIFFIES); } +static int issi_spi_nor_wait_till_ready(struct spi_nor *nor) +{ + unsigned long deadline; + int timeout = 0; + int ret; + + deadline = jiffies + DEFAULT_READY_WAIT_JIFFIES; + + while (!timeout) { + if (time_after_eq(jiffies, deadline)) + timeout = 1; + ret = spi_nor_sr_ready(nor); + if (ret < 0) + return ret; + if (ret) + return 0; + + cond_resched(); + } + + dev_err(nor->dev, "flash operation timed out\n"); + + return -ETIMEDOUT; +} /* * Erase the whole flash memory * @@ -367,6 +479,12 @@ if (ret) return ret; +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT + if ((nor->level) && (addr < nor->end_addr)) { + dev_err(nor->dev, "Error: The erase area was locked\n"); + return -EINVAL; + } +#endif /* whole-chip erase? */ if (len == mtd->size) { unsigned long timeout; @@ -745,6 +863,280 @@ return ret; } +#define SNOR_RD_MODES \ + (SNOR_MODE_SLOW | \ + SNOR_MODE_1_1_1 | \ + SNOR_MODE_1_1_2 | \ + SNOR_MODE_1_2_2 | \ + SNOR_MODE_1_1_4 | \ + SNOR_MODE_1_4_4) + +#define SNOR_WR_MODES \ + (SNOR_MODE_1_1_1 | \ + SNOR_MODE_1_1_4) + +static int spansion_quad_enable(struct spi_nor *nor); +static int macronix_quad_enable(struct spi_nor *nor); +static int gd_quad_enable(struct spi_nor *nor); +static int xtx_quad_enable(struct spi_nor *nor); +static int issi_quad_enable(struct spi_nor *nor); +static int puya_quad_enable(struct spi_nor *nor); +static int puya_quad_enable(struct spi_nor *nor); + +#define SNOR_EON_RD_MODES \ + (SNOR_MODE_SLOW | \ + SNOR_MODE_1_1_1 | \ + SNOR_MODE_1_1_2 | \ + SNOR_MODE_1_2_2) + +#define SNOR_EON_WR_MODES \ + (SNOR_MODE_1_1_1) + +static const struct spi_nor_basic_flash_parameter eon_params = { + .rd_modes = SNOR_EON_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_EON_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + +}; + +static const struct spi_nor_basic_flash_parameter esmt_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = macronix_quad_enable, + +}; + +#define SNOR_PARAGON_WR_MODES \ + (SNOR_MODE_1_1_1) + +static const struct spi_nor_basic_flash_parameter paragon_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_PARAGON_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = spansion_quad_enable, + +}; + +static const struct spi_nor_basic_flash_parameter gd_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = gd_quad_enable, + +}; + +static const struct spi_nor_basic_flash_parameter winbond_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(8, 0, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = spansion_quad_enable, + +}; + +static const struct spi_nor_basic_flash_parameter spansion_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = spansion_quad_enable, + +}; + +static const struct spi_nor_basic_flash_parameter issi_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = issi_quad_enable, + +}; + +#define SNOR_MXIC_WR_MODES \ + (SNOR_MODE_1_1_1 | \ + SNOR_MODE_1_4_4) + +static const struct spi_nor_basic_flash_parameter mxic_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(8, 16, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_MXIC_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_4_4] = SPINOR_OP_PP_1_4_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = macronix_quad_enable, + +}; + +static const struct spi_nor_basic_flash_parameter xmc_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(0, 24, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + +}; + +static const struct spi_nor_basic_flash_parameter micron_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(8, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(0, 40, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + +}; + +static const struct spi_nor_basic_flash_parameter micron_4k_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(1, 7, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(1, 9, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + .erase_types[1] = SNOR_OP_ERASE_4K(SPINOR_OP_BE_4K), +}; + +static const struct spi_nor_basic_flash_parameter xtx_params = { + .rd_modes = SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW] = SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4] = SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4] = SNOR_OP_READ(0, 24, SPINOR_OP_READ_1_4_4), + + .wr_modes = SNOR_MODE_1_1_1, + .page_programs[SNOR_MIDX_1_1_1] = SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4] = SPINOR_OP_PP_1_1_4, + + .erase_types[0] = SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = xtx_quad_enable, + +}; + +static const struct spi_nor_basic_flash_parameter puya_params = { + .rd_modes= SNOR_RD_MODES, + .reads[SNOR_MIDX_SLOW]= SNOR_OP_READ(0, 0, SPINOR_OP_READ), + .reads[SNOR_MIDX_1_1_1]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_FAST), + .reads[SNOR_MIDX_1_1_2]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_2), + .reads[SNOR_MIDX_1_2_2]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_2_2), + .reads[SNOR_MIDX_1_1_4]= SNOR_OP_READ(0, 8, SPINOR_OP_READ_1_1_4), + .reads[SNOR_MIDX_1_4_4]= SNOR_OP_READ(0, 24, SPINOR_OP_READ_1_4_4), + + .wr_modes= SNOR_WR_MODES, + .page_programs[SNOR_MIDX_1_1_1]= SPINOR_OP_PP, + .page_programs[SNOR_MIDX_1_1_4]= SPINOR_OP_PP_1_1_4, + + .erase_types[0]= SNOR_OP_ERASE_64K(SPINOR_OP_SE), + + .enable_quad_io = puya_quad_enable, +}; + +#define PARAMS(_name) .params = &_name##_params + /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ .id = { \ @@ -758,7 +1150,7 @@ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ - .flags = (_flags), + .flags = (_flags) #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ .id = { \ @@ -782,6 +1174,10 @@ .addr_width = (_addr_width), \ .flags = (_flags), +/* Different from spi-max-frequency in DTS, the clk here stands for the clock + * rate on SPI interface, it is half of the FMC CRG configuration */ +#define CLK_MHZ_2X(clk) .clkrate = (clk * 2000000), + /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. @@ -793,6 +1189,63 @@ * For historical (and compatibility) reasons (before we got above config) some * old entries may be missing 4K flag. */ +#define SPI_NOR_IDS_VER "1.2" + +/******* SPI Nor ID Table ************************************************************************ + * Version Manufacturer Chip Name Chipsize Block Vol Operation + * Macronix/MXIC MX25V1635F 2M 64K 3V3 + * 1.0 Macronix/MXIC MX25L1606E 2M 64K 3V3 + * Macronix/MXIC MX25L6436F 8M 64K 3V3 + * Macronix/MXIC MX25R6435F 8M 64K 1V8/3V3 Add 14chips + * Macronix/MXIC MX25U6435F 8M 64K 1V8 + * Macronix/MXIC MX25U12835F 16M 64K 1V8 + * Macronix/MXIC MX25F128XXX 16M 64K 3V3 + * Macronix/MXIC MX25U25635F/45G 32M 64K 1V8 25645G-DTR + * Macronix/MXIC MX25L(256/257) 32M 64K 3V3 25645G-DTR + * Macronix/MXIC MX25U51245G 64M 64K 1V8 51245G-DTR + * Macronix/MXIC MX25L51245G 64M 64K 3V3 + * Macronix/MXIC MX66U1G45GM 128M 64K 1V8 + * Spansion S25FL129P1 16M 64K 3V3 + * Spansion S25FL256S 32M 64K 3V3 + * Micron N25Q064A 8M 64K 3V3 + * Micron N25QL064A 8M 64K 3V3 + * Micron N25Q128A11/MT25QU128AB 16M 64K 1V8 + * Micron N25QL128A 16M 64K 3V3 + * Micron MT25QU256A 32M 64K 1V8 + * Micron MT25QL256A 32M 64K 3V3 + * Winbond W25Q16(B/C)V/S25FL016K 2M 64K 3V3 + * Winbond W25Q32(B/F)V 4M 64K 3V3 + * Winbond W25Q32FW 4M 64K 1V8 + * Winbond W25Q64FW 8M 64K 1V8 + * Winbond W25Q64FV(SPI)/W25Q64JV_IQ 8M 64K 3V3 + * Winbond W25Q128FW 16M 64K 1V8 + * Winbond W25Q128(B/F)V 16M 64K 3V3 + * Winbond W25Q128JV_IM 16M 64K 3V3 DTR + * Winbond W25Q256JWEIQ 32M 64K 1V8 + * Winbond W25Q256JWFIM 32M 64K 1V8 + * ESMT/CFEON EN25Q32B 4M 64K 3V3 + * ESMT/CFEON EN25Q64 8M 64K 3V3 + * ESMT/CFEON EN25Q128 16M 64K 3V3 + * ESMT/CFEON F25L64QA 8M 64K 3V3 + * GD GD25Q16C 2M 64K 3V3 + * GD GD25Q64 8M 64K 3V3 + * GD GD25LQ128 16M 64K 1V8 + * GD GD25Q128 16M 64K 3V3 + * GD GD25Q256 32M 64K 3V3 + * GD GD25LQ64C 8M 64K 1V8 + * GD GD25Q32 4M 64K 3V3 + * Paragon PN25F16S 2M 64K 3V3 + * Paragon PN25F32S 4M 64K 3V3 + * 1.1 ESMT/CFEON EN25QH64A 8M 64K 3V3 + * 1.2 XMC XM25QH64AHIG 8M 64K 3V3 + * XMC XM25QH128A 16M 64K 3V3 + * XMC XM25QH128B 16M 64K 3V3 + * Puya P25Q128H-SUH-IT 16M 64K 3V3 + * FM FM25Q64-SOB-T-G 8M 64K 3V3 + * FM FM25Q128-SOB-T-G 16M 64K 3V3 + * HUAHONG H25S64 8M 64K 3V3 + * HUAHONG H25S128 16M 64K 3V3 + ********************************************************************************************/ static const struct flash_info spi_nor_ids[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, @@ -812,44 +1265,60 @@ /* EON -- en25xxx */ { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, + SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, + { "en25qh32b-104hip2b", INFO(0x1c7016, 0, 64 * 1024, 64, + SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, + { "en25qh64a", INFO(0x1c7017, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, + { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, + { "en25qh128a", INFO(0x1c7018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, + /* GallopMemory */ + { "gm25q128a", INFO(0x1c4018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(eon), CLK_MHZ_2X(80) }, + + /* ESMT */ { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), PARAMS(esmt), CLK_MHZ_2X(84) }, /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "mr25h256", CAT25_INFO(32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, + { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, /* Fujitsu */ { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, - /* GigaDevice */ - { - "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - "gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, + /* GigaDevice 3.3V */ + { "gd25q16c", INFO(0xc84015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, + { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, + { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, + { "gd25q128/gd25q127", INFO(0xc84018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, + { "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(gd), CLK_MHZ_2X(80) }, + /* GigaDevice 1.8V */ + { "gd25lq16c", INFO(0xc86015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, + { "gd25lq64", INFO(0xc86017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, + { "gd25lq128", INFO(0xc86018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(gd), CLK_MHZ_2X(80) }, /* Intel/Numonyx -- xxxs33b */ { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, @@ -859,68 +1328,136 @@ /* ISSI */ { "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) }, - /* Macronix */ + { "IS25WP512M-RMLA3", INFO(0x9d701a, 0, 64 * 1024, 1024, + SPI_NOR_DUAL_READ), PARAMS(issi), CLK_MHZ_2X(80) }, + + /* Macronix/MXIC 3.3V */ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, - { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K + | SPI_NOR_DUAL_READ), CLK_MHZ_2X(80) }, + { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, - { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, - { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, - { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, + { "mx25l6436f", INFO(0xc22017, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), CLK_MHZ_2X(80) }, + { "mx25l12835f", INFO(0xc22018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(84) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, + { "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(84) }, + { "mx25l25673g", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_QUAD_READ + | SPI_NOR_4B_OPCODES) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, - { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, - - /* Micron */ - { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, - { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { "mx66l51235l/mx25l51245g", INFO(0xc2201a, 0, 64 * 1024, 1024, + SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(80)}, + { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ)}, + { "mx25v1635f", INFO(0xc22315, 0, 64 * 1024, 32 , + SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(80) }, + /* Macronix/MXIC Wide Voltage Range 1.65~3.6V */ + { "mx25r6435f", INFO(0xc22817, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), CLK_MHZ_2X(80) }, + /* Macronix/MXIC 1.8V */ + { "mx25u1633f", INFO(0xc22535, 0, 64 * 1024, 32, + SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(80) }, + { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(84) }, + { "mx25u12835f/mx25u12832f", INFO(0xc22538, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(mxic), CLK_MHZ_2X(84) }, + { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(84) }, + { "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(166) }, + { "mx66u1g45gm", INFO(0xc2253b, 0, 64 * 1024, 2048, + SPI_NOR_DUAL_READ | SPI_NOR_4B_OPCODES), PARAMS(mxic), CLK_MHZ_2X(80) }, + + /* Micron 3.3V */ + { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_DUAL_READ), + PARAMS(micron), CLK_MHZ_2X(84) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_DUAL_READ), + PARAMS(micron_4k), CLK_MHZ_2X(108) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ), + PARAMS(micron), CLK_MHZ_2X(108) }, + { "mt25ql256a", INFO(0x20ba19, 0x1044, 64 * 1024, 512, SPI_NOR_DUAL_READ), + PARAMS(micron), CLK_MHZ_2X(108) }, + { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR), + PARAMS(micron_4k) }, + { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR | SPI_NOR_DUAL_READ), + PARAMS(micron_4k), CLK_MHZ_2X(80) }, + /* Micron 1.8V */ + { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_DUAL_READ), + PARAMS(micron), CLK_MHZ_2X(108) }, + { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SPI_NOR_DUAL_READ), + PARAMS(micron), CLK_MHZ_2X(108) }, + { "mt25qu128a/n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ), + PARAMS(micron), CLK_MHZ_2X(108) }, + { "mt25qu256a", INFO(0x20bb19, 0, 64 * 1024, 512, + SPI_NOR_4B_OPCODES | SPI_NOR_DUAL_READ), PARAMS(micron), CLK_MHZ_2X(108) }, + { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, USE_FSR | SPI_NOR_DUAL_READ), + PARAMS(micron_4k), CLK_MHZ_2X(80) }, + + /* XMC */ + { "xm25qh64a", INFO(0x207017, 0, 64 * 1024, 128, SPI_NOR_DUAL_READ), + PARAMS(xmc), CLK_MHZ_2X(80) }, + { "xm25qh64b", INFO(0x206017, 0, 64 * 1024, 128, SPI_NOR_DUAL_READ), + PARAMS(xmc), CLK_MHZ_2X(80) }, + { "xm25qh128a", INFO(0x207018, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ), + PARAMS(xmc), CLK_MHZ_2X(80) }, + { "xm25qh128b", INFO(0x206018, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ), + PARAMS(xmc), CLK_MHZ_2X(80) }, + { "xm25qh64chiq", INFO(0x204017, 0, 64 * 1024, 128, SPI_NOR_DUAL_READ), + PARAMS(xmc), CLK_MHZ_2X(80) }, + { "xm25qh128chiq", INFO(0x204018, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ), + PARAMS(xmc), CLK_MHZ_2X(80) }, /* PMC */ - { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, - { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, - { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, + { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, + { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ - { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, + SPI_NOR_4B_OPCODES | SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, + { "s25fl127s/129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(108) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, - { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, - { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, - { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, - { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, - { "s25fl004k", INFO(0xef4013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, - { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, - { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) }, + { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K + | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl128lagmfi010z", INFO(0x016018, 0, 64 * 1024, 256, + SPI_NOR_QUAD_READ)}, + { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, + { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, + { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, + { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, + { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, + { "s25fl004k", INFO(0xef4013, 0, 64 * 1024, 8, SECT_4K + | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K + | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "w25Q16jv-iq/s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(84) }, + /* { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K + | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, */ + { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, + { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, + { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K + | SPI_NOR_DUAL_READ) }, /* SST -- large erase sizes are "overlays", "sectors" are 4K */ { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, @@ -947,6 +1484,9 @@ { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, + { "GM25Q128ASIG", INFO(0x1C4018, 0, 64 * 1024, 256, 0) }, + { "NM25Q128EVB", INFO(0x522118, 0, 64 * 1024, 256, 0) }, + { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, @@ -972,43 +1512,109 @@ { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + /* Winbond 3.3V-- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) }, { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, + { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K + | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, - { - "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, + { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { - "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, - { - "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, + { "w25q64fv(spi)/w25q64jv_iq", INFO(0xef4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, + { "w25q128(b/f)v", INFO(0xef4018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) }, + { "w25q128jv_im", INFO(0xef7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) }, +#ifdef CONFIG_AUTOMOTIVE_GRADE + { "w25q256(f/j)v", INFO(0xef4019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ), PARAMS(winbond), CLK_MHZ_2X(80) }, +#else + { "w25q256(f/j)v", INFO(0xef4019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES), PARAMS(winbond), CLK_MHZ_2X(80) }, +#endif + /* Winbond 1.8V */ + { "w25q32fw", INFO(0xef6016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) }, + { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) }, + { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB), PARAMS(winbond), CLK_MHZ_2X(80) }, + { "w25q256jw-im", INFO(0xef8019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES), + PARAMS(winbond), CLK_MHZ_2X(80) }, + { "w25q256jw-iq", INFO(0xef6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES), + PARAMS(winbond), CLK_MHZ_2X(80) }, /* Catalyst / On Semiconductor -- non-JEDEC */ - { "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c03", CAT25_INFO( 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "cat25c11", CAT25_INFO(16, 8, 16, 1, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, + { "cat25c03", CAT25_INFO(32, 8, 16, 2, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, + { "cat25c09", CAT25_INFO(28, 8, 32, 2, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, + { "cat25c17", CAT25_INFO(256, 8, 32, 2, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, + { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE + | SPI_NOR_NO_FR) }, + /* Paragon 3.3V */ + { "pn25f16s", INFO(0xe04015, 0, 64 * 1024, 32, + SPI_NOR_DUAL_READ), PARAMS(paragon), CLK_MHZ_2X(80) }, + { "pn25f32s", INFO(0xe04016, 0, 64 * 1024, 64, + SPI_NOR_DUAL_READ), PARAMS(paragon), CLK_MHZ_2X(80) }, + + /* XTX */ + { "xt25f16bssigu", INFO(0x0b4015, 0, 64 * 1024, 32, + SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(80) }, + + { "xt25f32bssigu-s", INFO(0x0b4016, 0, 64 * 1024, 64, + SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(80) }, + + { "xt25f128b", INFO(0x0b4018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) }, + + { "xt25f64b", INFO(0x0b4017, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) }, + + /*puya 3.3V */ + {"p25q128h", INFO(0x856018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(puya), CLK_MHZ_2X(80) }, + + /* FM 3.3v */ + { "FM25Q64-SOB-T-G",INFO(0xa14017, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + { "FM25Q128-SOB-T-G",INFO(0xa14018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + + /* HUAHONG 3.3v */ + { "H25S64",INFO(0x684017, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + + { "H25S128",INFO(0x684018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + + { "ZB25VQ64A",INFO(0x5e4017, 0, 64 * 1024, 128, + SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + { "ZB25VQ128ASIG",INFO(0x5e4018, 0, 64 * 1024, 256, + SPI_NOR_DUAL_READ), PARAMS(spansion), CLK_MHZ_2X(80) }, + + /* SiliconKaiser 3.3v */ + { "sk25p128", INFO(0x256018, 0, 64 * 1024, 256, SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) }, + + { "sk25p64", INFO(0x256017, 0, 64 * 1024, 128, SPI_NOR_DUAL_READ), PARAMS(xtx), CLK_MHZ_2X(70) }, + { }, }; @@ -1024,6 +1630,11 @@ return ERR_PTR(tmp); } + if ((id[0] == 0xff) || (id[0] == 0x00)) { + dev_err(nor->dev, "unrecognized Manufacturer ID\n"); + return ERR_PTR(-ENODEV); + } + for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { info = &spi_nor_ids[tmp]; if (info->id_len) { @@ -1036,6 +1647,36 @@ return ERR_PTR(-ENODEV); } +static int puya_quad_enable(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = read_cr(nor); + if ((unsigned int)ret & CR_QUAD_EN_SPAN) + return 0; + + val = (((unsigned int)ret & 0xff) | CR_QUAD_EN_SPAN); + write_enable(nor); + + ret = write_sr2(nor, val); + if (ret < 0) { + dev_err(nor->dev, + "error while writing status register-2\n"); + return -EINVAL; + } + + if (spi_nor_wait_till_ready(nor)) + return 1; + + /* read back and check it */ + ret = read_cr(nor); + if ((unsigned int)ret & CR_QUAD_EN_SPAN) + return 0; + else + return 1; +} + static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -1167,14 +1808,22 @@ ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); if (ret) return ret; +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT + if (nor->level && (to < nor->end_addr)) { + dev_err(nor->dev, "Error: The DMA write area was locked\n"); + return -EINVAL; + } +#endif for (i = 0; i < len; ) { ssize_t written; page_offset = (to + i) & (nor->page_size - 1); +#ifndef CONFIG_SPI_GOKE_SFC WARN_ONCE(page_offset, "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.", page_offset); +#endif /* the size of data remaining on the first page */ page_remain = min_t(size_t, nor->page_size - page_offset, len - i); @@ -1211,15 +1860,22 @@ val = read_sr(nor); if (val < 0) return val; + + if ((unsigned int)val & SR_QUAD_EN_MX) + return 0; + + /* Update the Quad Enable bit. */ + dev_dbg(nor->dev, "setting Macronix Quad Enable (non-volatile) bit\n"); + write_enable(nor); - write_sr(nor, val | SR_QUAD_EN_MX); + write_sr(nor, (u8)val | SR_QUAD_EN_MX); if (spi_nor_wait_till_ready(nor)) return 1; ret = read_sr(nor); - if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + if (!(ret > 0 && ((unsigned int)ret & SR_QUAD_EN_MX))) { dev_err(nor->dev, "Macronix Quad bit not set\n"); return -EINVAL; } @@ -1227,6 +1883,41 @@ return 0; } +static int xtx_quad_enable(struct spi_nor *nor) +{ + u8 ret, val_h,val_l; + /* read SR high 8bit*/ + val_h = read_cr(nor); + if (val_h < 0) + return val_h; + + if (val_h & SR_QUAD_EN_XTX) + return 0; + + /* Update the Quad Enable bit. */ + dev_dbg(nor->dev, "setting xtx Quad Enable (non-volatile) bit\n"); + + write_enable(nor); + + /* read SR low 8bit*/ + val_l = read_sr(nor); + + /* write SR */ + nor->cmd_buf[0] = val_l; + nor->cmd_buf[1] = val_h; + nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2); + + if (spi_nor_wait_till_ready(nor)) + return 1; + + ret = read_cr(nor); + if (!(ret > 0 && (ret & SR_QUAD_EN_XTX))) { + dev_err(nor->dev, "xtx Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} /* * Write status Register and configuration register with 2 bytes * The first byte will be written to the status register, while the @@ -1243,29 +1934,168 @@ static int spansion_quad_enable(struct spi_nor *nor) { - int ret; - int quad_en = CR_QUAD_EN_SPAN << 8; + unsigned int ret; + u16 val; + + ret = read_cr(nor); + if (ret & CR_QUAD_EN_SPAN) + return 0; + + /* Update the Quad Enable bit. */ + dev_dbg(nor->dev, "setting Quad Enable (non-volatile) bit\n"); + + val = ((ret & 0xff) | CR_QUAD_EN_SPAN) << 8; + + ret = read_sr(nor); + val |= (ret & 0xff); + + write_enable(nor); + + ret = write_sr_cr(nor, val); + if (ret < 0) { + dev_err(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + if (spi_nor_wait_till_ready(nor)) + return 1; + + /* read back and check it */ + ret = read_cr(nor); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int issi_quad_enable(struct spi_nor *nor) +{ + unsigned int ret; + u16 val; + + ret = read_sr(nor); + if (ret & QUAD_EN_ISSI) + return 0; + + /* Update the Quad Enable bit. */ + dev_dbg(nor->dev, "setting Quad Enable (non-volatile) bit\n"); + + val = ((ret & 0xff) | QUAD_EN_ISSI); write_enable(nor); - ret = write_sr_cr(nor, quad_en); + ret = write_sr(nor, val); if (ret < 0) { dev_err(nor->dev, "error while writing configuration register\n"); return -EINVAL; } + if (issi_spi_nor_wait_till_ready(nor)) + return 1; + + /* read back and check it */ + ret = read_sr(nor); + if (!(ret > 0 && (ret & QUAD_EN_ISSI))) { + dev_err(nor->dev, "ISSI Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int micron_quad_enable(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + + write_enable(nor); + + /* set EVCR, enable quad I/O */ + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1); + if (ret < 0) { + dev_err(nor->dev, "error while writing EVCR register\n"); + return ret; + } + ret = spi_nor_wait_till_ready(nor); - if (ret) { + if (ret) + return ret; + + /* read EVCR and check it */ + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + if (val & EVCR_QUAD_EN_MICRON) { + dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); + return -EINVAL; + } + + return 0; +} + +static int gd_quad_enable(struct spi_nor *nor) +{ + int ret; + u16 val; + + /* First, Quad Enable for 16-Pin GD flash, use WRSR[01h] cmd */ + ret = read_cr(nor); + val = (((unsigned int)ret & 0xff) | CR_QUAD_EN_SPAN) << 8; + + ret = read_sr(nor); + val |= ((unsigned int)ret & 0xff); + + write_enable(nor); + + ret = write_sr_cr(nor, val); + if (ret < 0) { dev_err(nor->dev, - "timeout while writing configuration register\n"); + "error while writing config and status register\n"); + return -EINVAL; + } + + if (spi_nor_wait_till_ready(nor)) + return 1; + + /* read back and check it */ + ret = read_cr(nor); + if ((unsigned int)ret & CR_QUAD_EN_SPAN) + return 0; + + /* Second, Quad Enable for 8-Pin GD flash, use WRCR[31h] cmd */ + ret = read_sr(nor); + if (!((unsigned int)ret & SR_WEL)) + write_enable(nor); + + ret = read_cr(nor); + nor->cmd_buf[0] = ((unsigned int)ret & 0xff) | CR_QUAD_EN_SPAN; + + ret = nor->write_reg(nor, SPINOR_OP_WRCR, nor->cmd_buf, 1); + if (ret < 0) { + dev_err(nor->dev, "error while writing config register\n"); return ret; } + if (spi_nor_wait_till_ready(nor)) + return 1; + /* read back and check it */ ret = read_cr(nor); - if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { - dev_err(nor->dev, "Spansion Quad bit not set\n"); + if (!(ret > 0 && ((unsigned int)ret & CR_QUAD_EN_SPAN))) { + dev_err(nor->dev, "GigaDevice Quad bit not set\n"); return -EINVAL; } @@ -1277,6 +2107,7 @@ int status; switch (JEDEC_MFR(info)) { + case SNOR_MFR_ESMT: case SNOR_MFR_MACRONIX: status = macronix_quad_enable(nor); if (status) { @@ -1285,7 +2116,40 @@ } return status; case SNOR_MFR_MICRON: - return 0; + status = micron_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Micron quad-read not enabled\n"); + return -EINVAL; + } + return status; + case SNOR_MFR_GD: + status = gd_quad_enable(nor); + if (status) { + dev_err(nor->dev, "GD quad-read not enabled\n"); + return -EINVAL; + } + return status; + case SNOR_MFR_XTX: + status = xtx_quad_enable(nor); + if (status) { + dev_err(nor->dev, "xtx quad-read not enabled\n"); + return -EINVAL; + } + return status; + case SNOR_MFR_PUYA: + status = puya_quad_enable(nor); + if (status) { + dev_err(nor->dev, "puya quad-read not enabled\n"); + return -EINVAL; + } + return status; + case SNOR_MFR_ISSI: + status = issi_quad_enable(nor); + if (status) { + dev_err(nor->dev, "puya quad-read not enabled\n"); + return -EINVAL; + } + return status; default: status = spansion_quad_enable(nor); if (status) { @@ -1307,8 +2171,497 @@ return 0; } -int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT +static void spi_lock_update_address(struct spi_nor *nor, const struct flash_info *info) +{ + unsigned int lock_level_max, sectorsize, chipsize; + + if (!nor->level) { + nor->end_addr = 0; + dev_warn(nor->dev, "all blocks is unlocked.\n"); + return; + } + + sectorsize = info->sector_size; + chipsize = sectorsize * info->n_sectors; + lock_level_max = nor->lock_level_max; + + switch (JEDEC_MFR(info)) { + case SNOR_MFR_MACRONIX: + if (chipsize == _2M) { + if ((nor->level != lock_level_max) + && (nor->level != 1)) + nor->end_addr = chipsize - (sectorsize << + (lock_level_max - nor->level - 1)); + else + nor->end_addr = chipsize; + return; + } + + if (chipsize != _8M) + break; + case SNOR_MFR_ESMT: + /* this case is for ESMT and MXIC 8M devices */ + if (nor->level != lock_level_max) + nor->end_addr = chipsize - (sectorsize + << (lock_level_max - nor->level)); + else + nor->end_addr = chipsize; + return; + case SNOR_MFR_EON: + if (nor->level != lock_level_max) + nor->end_addr = chipsize - (sectorsize + << (nor->level - 1)); + else + nor->end_addr = chipsize; + return; + default: + break; + } + + /* general case */ + nor->end_addr = chipsize >> (lock_level_max - nor->level); +} + +static unsigned char bsp_bp_to_level(struct spi_nor *nor, + const struct flash_info *info, unsigned int bp_num) +{ + int ret; + unsigned char val; + unsigned char level; + unsigned int chipsize; + + ret = spi_nor_wait_till_ready(nor); + BUG_ON(ret); + + ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading SR\n", ret); + return ret; + } + + if (bp_num == BP_NUM_3) + level = (val & SPI_NOR_SR_BP_MASK_3) >> SPI_NOR_SR_BP0_SHIFT; + else + level = (val & SPI_NOR_SR_BP_MASK_4) >> SPI_NOR_SR_BP0_SHIFT; + + dev_dbg(nor->dev, "the current level[%d]\n", level); + + if (bp_num == BP_NUM_4) { + nor->lock_level_max = LOCK_LEVEL_MAX(bp_num) - 5; + chipsize = info->sector_size * info->n_sectors; + if ((JEDEC_MFR(info) == SNOR_MFR_MACRONIX) + && (chipsize == _16M)) + nor->lock_level_max--; + } else + nor->lock_level_max = LOCK_LEVEL_MAX(bp_num); + dev_dbg(nor->dev, "Get the max bp level: [%d]\n", + nor->lock_level_max); + + return level; +} + +static void bsp_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info) +{ + unsigned int chipsize; + struct device *dev = nor->dev; + + chipsize = info->sector_size * info->n_sectors; + + /* read the BP bit in RDSR to check whether nor is lock or not */ + switch (JEDEC_MFR(info)) { + case SNOR_MFR_GD: + case SNOR_MFR_FM: + case SNOR_MFR_ESMT: + case SNOR_MFR_EON: + case SNOR_MFR_SPANSION: + /* BP bit convert to lock level */ + nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); + break; + case SNOR_MFR_WINBOND: + if (!strcmp("w25q128(b/f)v", info->name)) { + dev_info(nor->dev, "Force global unlock\n"); + write_enable(nor); + /* Global Block/Sector Unlock, + * see 8.2.42 Global Block/Sector Unlock (98h) */ + nor->write_reg(nor, 0x98, NULL, 0); + write_disable(nor); + } + /* BP bit convert to lock level */ + if (chipsize <= _16M) + nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); + else + nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); + break; + case SNOR_MFR_MACRONIX: + + /* BP bit convert to lock level */ + if (chipsize <= _8M) + nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); + else + nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); + break; + case SNOR_MFR_XTX: + /* BP bit convert to lock level */ + nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); + break; + default: + goto usage; + } + + spi_lock_update_address(nor, info); + if (nor->end_addr) + dev_info(dev, "Address range [0 => %#x] is locked.\n", + nor->end_addr); + return; +usage: + dev_err(dev, "The ID: %#x isn't in the BP table," + " Current device can't not protect\n", + JEDEC_MFR(info)); +} +#endif/* CONFIG_GOKE_SPI_BLOCK_PROTECT */ + +static int spi_nor_midx2proto(int midx, enum spi_nor_protocol *proto) +{ + switch (midx) { + case SNOR_MIDX_SLOW: + case SNOR_MIDX_1_1_1: + *proto = SNOR_PROTO_1_1_1; + break; + + case SNOR_MIDX_1_1_2: + *proto = SNOR_PROTO_1_1_2; + break; + + case SNOR_MIDX_1_2_2: + *proto = SNOR_PROTO_1_2_2; + break; + case SNOR_MIDX_1_1_4: + *proto = SNOR_PROTO_1_1_4; + break; + + case SNOR_MIDX_1_4_4: + *proto = SNOR_PROTO_1_4_4; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int spi_nor_sr3_to_reset(struct spi_nor *nor) +{ + int ret; + unsigned char val; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading Status Reg 3.\n", ret); + return ret; + } + + if (SPI_NOR_GET_RST(val)) { + dev_dbg(nor->dev, "Device has worked on RESET#.\n"); + return 0; + } + + dev_dbg(nor->dev, "Start to enable RESET# function.\n"); + val = SPI_NOR_SET_RST(val); + + nor->write_reg(nor, SPINOR_OP_WRSR3, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error while writing Status Reg 3.\n"); + return ret; + } + + dev_dbg(nor->dev, "Enable RESET# function success.\n"); + + return 0; +} + +static int spi_nor_reset_pin_enable(struct spi_nor *nor, + const struct flash_info *info) +{ + switch (JEDEC_MFR(info)) { + case SNOR_MFR_WINBOND: + case SNOR_MFR_GD: + return spi_nor_sr3_to_reset(nor); + default: + return 0; + } +} + +static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_basic_flash_parameter *params, + const struct spi_nor_modes *modes) +{ + bool enable_quad_io; + u32 rd_modes, wr_modes; + const struct spi_nor_erase_type *erase_type; + const struct spi_nor_read_op *read; + int rd_midx, wr_midx, err = 0; +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + int i = 0; +#endif + rd_modes = modes->rd_modes; + wr_modes = modes->wr_modes; + + /* Setup read operation. */ + rd_midx = fls(params->rd_modes & rd_modes) - 1; + if (spi_nor_midx2proto(rd_midx, &nor->read_proto)) { + dev_err(nor->dev, "invalid (fast) read\n"); + return -EINVAL; + } + read = ¶ms->reads[rd_midx]; + nor->read_opcode = read->opcode; + nor->read_dummy = read->num_mode_clocks + read->num_wait_states; + + /* Set page program op code and protocol. */ + wr_midx = fls(params->wr_modes & wr_modes) - 1; + if (spi_nor_midx2proto(wr_midx, &nor->write_proto)) { + dev_err(nor->dev, "invalid page program\n"); + return -EINVAL; + } + nor->program_opcode = params->page_programs[wr_midx]; + + /* Set sector erase op code and size. */ + erase_type = ¶ms->erase_types[0]; +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + for (i = 1; i < SNOR_MAX_ERASE_TYPES; ++i) + if (params->erase_types[i].size == 0x0c) + erase_type = ¶ms->erase_types[i]; +#endif + nor->erase_opcode = erase_type->opcode; + nor->mtd.erasesize = (1 << erase_type->size); + + enable_quad_io = (SNOR_PROTO_DATA_FROM_PROTO(nor->read_proto) == 4 || + SNOR_PROTO_DATA_FROM_PROTO(nor->write_proto) == 4); + + /* Enable Quad I/O if needed. */ + if (enable_quad_io && params->enable_quad_io) { + err = params->enable_quad_io(nor); + if (err) { + dev_err(nor->dev, + "failed to enable the Quad I/O mode\n"); + return err; + } + } + + /* + * Fix erase protocol if needed, read and write protocols should + * already be valid. + */ + nor->erase_proto = SNOR_PROTO_1_1_1; + + dev_dbg(nor->dev, + "(Fast) Read: opcode=%02Xh, protocol=%03x, mode=%u, wait=%u\n", + nor->read_opcode, nor->read_proto, + read->num_mode_clocks, read->num_wait_states); + dev_dbg(nor->dev, + "Page Program: opcode=%02Xh, protocol=%03x\n", + nor->program_opcode, nor->write_proto); + dev_dbg(nor->dev, + "Sector Erase: opcode=%02Xh, protocol=%03x, sector size=%zu\n", + nor->erase_opcode, nor->erase_proto, (size_t)nor->mtd.erasesize); + + return 0; +} + +#define SR_SEC BIT(6) + +static char* winbond_sr1txt(char buf[512], unsigned char val) { + if (val & SR_WIP) { + strcat(buf, ",BUSY"); + } + if (val & SR_WEL) { + strcat(buf, ",WEL"); + } + if (val & SR_BP0) { + strcat(buf, ",BP0"); + } + if (val & SR_BP1) { + strcat(buf, ",BP1"); + } + if (val & SR_BP2) { + strcat(buf, ",BP2"); + } + if (val & SR_TB) { + strcat(buf, ",TB"); + } + if (val & SR_SEC) { + strcat(buf, ",SEC"); + } + if (val & SR_SRWD) { + strcat(buf, ",SRP0"); + } + if (strlen(buf)) buf += 1; + return buf; +} + +#define SR2_SRP1 BIT(0) +#define SR2_QE BIT(1) +#define SR2_R BIT(2) +#define SR2_LB1 BIT(3) +#define SR2_LB2 BIT(4) +#define SR2_LB3 BIT(5) +#define SR2_CMP BIT(6) +#define SR2_SUS BIT(7) + +static char* winbond_sr2txt(char buf[512], unsigned char val) { + if (val & SR2_SRP1) { + strcat(buf, ",SRP1"); + } + if (val & SR2_QE) { + strcat(buf, ",QE"); + } + if (val & SR2_LB1) { + strcat(buf, ",LB1"); + } + if (val & SR2_LB2) { + strcat(buf, ",LB2"); + } + if (val & SR2_LB3) { + strcat(buf, ",LB3"); + } + if (val & SR2_CMP) { + strcat(buf, ",CMP"); + } + if (val & SR2_SUS) { + strcat(buf, ",SUS"); + } + if (strlen(buf)) buf += 1; + return buf; +} + +#define SR3_WPS BIT(2) +#define SR3_DRV0 BIT(5) +#define SR3_DRV1 BIT(6) +#define SR3_HOLD BIT(7) + +static char* winbond_sr3txt(char buf[512], unsigned char val) { + if (val & SR3_WPS) { + strcat(buf, ",WPS"); + } + if (val & SR3_DRV0) { + strcat(buf, ",DRV0"); + } + if (val & SR3_DRV1) { + strcat(buf, ",DRV1"); + } + if (val & SR3_HOLD) { + strcat(buf, ",HOLD"); + } + if (strlen(buf)) buf += 1; + return buf; +} + +static int spi_nor_config(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_basic_flash_parameter *params, + struct spi_nor_modes *modes) { + int ret; + unsigned char cval,val; + + if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX){ + val = read_sr(nor); + if (val < 0) + return val; + + /* read Configuration Register for macronix's spi nor flash */ + ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &cval, 1); + if(ret < 0){ + dev_err(nor->dev, "error %d reading config Reg.\n", ret); + return ret; + } + + /* check the bit[6:7] whether is set in uboot when use DTR mode;if it was set and clear it. */ + /* pay attention to sequence of issuing WRSR instruction */ + if (cval & CR_DUMMY_CYCLE){ + write_enable(nor); + nor->cmd_buf[0]=val; + nor->cmd_buf[1]=(cval & (~CR_DUMMY_CYCLE)); + ret = nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2); + } + } else if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) { + unsigned char sr1, sr2, sr3; + char sr1txt[256] = {0}, sr2txt[256] = {0}, sr3txt[256] = {0}; + + sr1 = read_sr(nor); + if (sr1 < 0) + return sr1; + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); + if(ret < 0){ + dev_err(nor->dev, "error %d reading config Reg.\n", ret); + return ret; + } + ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &sr3, 1); + if(ret < 0){ + dev_err(nor->dev, "error %d reading config Reg.\n", ret); + return ret; + } + dev_info(nor->dev, "Winbond: SR1 [%s], SR2 [%s], SR3 [%s]\n", + winbond_sr1txt(sr1txt, sr1), winbond_sr2txt(sr2txt, sr2), + winbond_sr3txt(sr3txt, sr3)); + } + + if (params) { + ret = spi_nor_setup(nor, info, params, modes); + if (ret) + return ret; + } else if (modes->rd_modes & SNOR_MODE_1_1_4 && + info->flags & SPI_NOR_QUAD_READ) { + /* + * This branch is spcially for some devices which can + * not be stated by params, but only SPI_NOR_QUAD_READ, + * it just supports the protocol 1_1_4. + */ + if (spi_nor_wait_till_ready(nor)) + return 1; + + ret = set_quad_mode(nor, info); + if (ret) { + dev_err(nor->dev, "quad mode not supported\n"); + return ret; + } + nor->read_proto = SNOR_PROTO_1_1_4; + nor->read_opcode = SPINOR_OP_READ_1_1_4; + nor->read_dummy = 8; + } else if (modes->rd_modes & SNOR_MODE_1_1_2 && + info->flags & SPI_NOR_DUAL_READ) { + /* + * This branch is spcially for some devices which can + * not be stated by params, but only SPI_NOR_DUAL_READ, + * it just supports the protocol 1_1_2. + */ + nor->read_proto = SNOR_PROTO_1_1_2; + nor->read_opcode = SPINOR_OP_READ_1_1_2; + nor->read_dummy = 8; + } else { + if (modes->rd_modes & SNOR_MODE_1_1_1) { + nor->read_opcode = SPINOR_OP_READ_FAST; + nor->read_dummy = 8; + } else { + nor->read_opcode = SPINOR_OP_READ; + nor->read_dummy = 0; + } + } + + if (!(modes->rd_modes & (SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4))) { + ret = spi_nor_reset_pin_enable(nor, info); + if (ret < 0) { + dev_err(nor->dev, "Enable RESET# fail.\n"); + return ret; + } + } + + return 0; +} + +int spi_nor_scan(struct spi_nor *nor, const char *name, + struct spi_nor_modes *modes) +{ + const struct spi_nor_basic_flash_parameter *params = NULL; const struct flash_info *info = NULL; struct device *dev = nor->dev; struct mtd_info *mtd = &nor->mtd; @@ -1320,11 +2673,19 @@ if (ret) return ret; + /* Reset SPI protocol for all commands */ + nor->erase_proto = SNOR_PROTO_1_1_1; + nor->read_proto = SNOR_PROTO_1_1_1; + nor->write_proto = SNOR_PROTO_1_1_1; + if (name) info = spi_nor_match_id(name); /* Try to auto-detect if chip name wasn't specified or not found */ - if (!info) + if (!info) { + dev_info(dev, "SPI Nor ID Table Version %s\n", SPI_NOR_IDS_VER); info = spi_nor_read_id(nor); + } + if (IS_ERR_OR_NULL(info)) return -ENOENT; @@ -1351,9 +2712,15 @@ info = jinfo; } } + if (info->params) + params = info->params; mutex_init(&nor->lock); +#ifdef CONFIG_GOKE_SPI_BLOCK_PROTECT + /* NOR block protection support */ + bsp_get_spi_lock_info(nor, info); +#else /* * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up * with the software protection bits set @@ -1367,6 +2734,7 @@ write_sr(nor, 0); spi_nor_wait_till_ready(nor); } +#endif if (!mtd->name) mtd->name = dev_name(dev); @@ -1380,7 +2748,10 @@ /* NOR protection support for STmicro/Micron chips and similar */ if (JEDEC_MFR(info) == SNOR_MFR_MICRON || - info->flags & SPI_NOR_HAS_LOCK) { + JEDEC_MFR(info) == SNOR_MFR_WINBOND || + JEDEC_MFR(info) == SNOR_MFR_XTX || + JEDEC_MFR(info) == SNOR_MFR_FM || + info->flags & SPI_NOR_HAS_LOCK) { nor->flash_lock = stm_lock; nor->flash_unlock = stm_unlock; nor->flash_is_locked = stm_is_locked; @@ -1428,92 +2799,61 @@ if (np) { /* If we were instantiated by DT, use it */ if (of_property_read_bool(np, "m25p,fast-read")) - nor->flash_read = SPI_NOR_FAST; + modes->rd_modes |= SNOR_MODE_1_1_1; else - nor->flash_read = SPI_NOR_NORMAL; + modes->rd_modes &= ~SNOR_MODE_1_1_1; } else { /* If we weren't instantiated by DT, default to fast-read */ - nor->flash_read = SPI_NOR_FAST; + modes->rd_modes |= SNOR_MODE_1_1_1; } /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & SPI_NOR_NO_FR) - nor->flash_read = SPI_NOR_NORMAL; - - /* Quad/Dual-read mode takes precedence over fast/normal */ - if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { - ret = set_quad_mode(nor, info); - if (ret) { - dev_err(dev, "quad mode not supported\n"); - return ret; - } - nor->flash_read = SPI_NOR_QUAD; - } else if (mode == SPI_NOR_DUAL && info->flags & SPI_NOR_DUAL_READ) { - nor->flash_read = SPI_NOR_DUAL; - } - - /* Default commands */ - switch (nor->flash_read) { - case SPI_NOR_QUAD: - nor->read_opcode = SPINOR_OP_READ_1_1_4; - break; - case SPI_NOR_DUAL: - nor->read_opcode = SPINOR_OP_READ_1_1_2; - break; - case SPI_NOR_FAST: - nor->read_opcode = SPINOR_OP_READ_FAST; - break; - case SPI_NOR_NORMAL: - nor->read_opcode = SPINOR_OP_READ; - break; - default: - dev_err(dev, "No Read opcode defined\n"); - return -EINVAL; - } + modes->rd_modes &= ~SNOR_MODE_1_1_1; nor->program_opcode = SPINOR_OP_PP; + /* + * Configure the SPI memory: + * - select op codes for (Fast) Read, Page Program and Sector Erase. + * - set the number of dummy cycles (mode cycles + wait states). + * - set the SPI protocols for register and memory accesses. + * - set the Quad Enable bit if needed (required by SPI x-y-4 protos). + */ + ret = spi_nor_config(nor, info, params, modes); + if (ret) + return ret; + if (info->addr_width) nor->addr_width = info->addr_width; else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; - if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { - /* Dedicated 4-byte command set */ - switch (nor->flash_read) { - case SPI_NOR_QUAD: - nor->read_opcode = SPINOR_OP_READ4_1_1_4; - break; - case SPI_NOR_DUAL: - nor->read_opcode = SPINOR_OP_READ4_1_1_2; - break; - case SPI_NOR_FAST: - nor->read_opcode = SPINOR_OP_READ4_FAST; - break; - case SPI_NOR_NORMAL: - nor->read_opcode = SPINOR_OP_READ4; - break; - } - nor->program_opcode = SPINOR_OP_PP_4B; - /* No small sector erase for 4-byte command set */ - nor->erase_opcode = SPINOR_OP_SE_4B; - mtd->erasesize = info->sector_size; - } else + if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || + info->flags & SPI_NOR_4B_OPCODES) + spi_nor_set_4byte_opcodes(nor, info); + else set_4byte(nor, info, 1); } else { nor->addr_width = 3; } + /* choose the suitable clockrate */ + if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) /* device supports dual or quad */ + && (modes->rd_modes & (~SNOR_MODE_SLOW)) /* controller supports fast mode */ + && info->clkrate) + nor->clkrate = info->clkrate; + else + nor->clkrate = 24000000; + if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { dev_err(dev, "address width is too large: %u\n", nor->addr_width); return -EINVAL; } - nor->read_dummy = spi_nor_read_dummy_cycles(nor); - - dev_info(dev, "%s (%lld Kbytes)\n", info->name, - (long long)mtd->size >> 10); + dev_info(dev, "%s (Chipsize %lld Mbytes, Blocksize %uKiB)\n", + info->name, (long long)mtd->size >> 20, mtd->erasesize / 1024); dev_dbg(dev, "mtd .name = %s, .size = 0x%llx (%lldMiB), " @@ -1547,6 +2887,64 @@ return NULL; } +/******************************************************************************/ +void spi_nor_driver_shutdown(struct spi_nor *nor) +{ + /* disable 4-byte addressing if the device exceeds 16MiB */ + if (nor->addr_width == 4) { + const struct flash_info *info = NULL; + + info = spi_nor_read_id(nor); + set_4byte(nor, info, 0); + } + return; +} + +#ifdef CONFIG_PM +/******************************************************************************/ +int spi_nor_suspend(struct spi_nor *nor, pm_message_t state) +{ + return spi_nor_wait_till_ready(nor); +} + +/******************************************************************************/ +int spi_nor_resume(struct spi_nor *nor) +{ + int ret; + const struct flash_info *info = NULL; + const struct spi_nor_basic_flash_parameter *params = NULL; + struct spi_nor_modes modes = { + .rd_modes = SNOR_MODE_SLOW, + .wr_modes = SNOR_MODE_1_1_1, + }; + + modes.rd_modes |= SNOR_MODE_1_1_1 + | SNOR_MODE_1_1_2 + | SNOR_MODE_1_2_2; +#ifndef CONFIG_CLOSE_SPI_8PIN_4IO + modes.rd_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4; + modes.wr_modes |= SNOR_MODE_1_1_4 | SNOR_MODE_1_4_4; +#endif + + if (!info) + info = spi_nor_read_id(nor); + + /* Quad mode takes precedence over fast/normal */ + if (info->params) + params = info->params; + + ret = spi_nor_config(nor, info, params, &modes); + if (ret) + return ret; + + /* enable 4-byte addressing if the device exceeds 16MiB */ + if (nor->addr_width == 4 && JEDEC_MFR(info) != SNOR_MFR_SPANSION) + set_4byte(nor, info, 1); + + return 0; +} +#endif /* End of CONFIG_PM */ + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); MODULE_AUTHOR("Mike Lavender");