firmware/br-ext-chip-goke/board/gk7205v200/kernel/patches/00_drivers-mtd-spi-nor-spi-...

2136 lines
68 KiB
Diff

--- 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 = &params->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 = &params->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 = &params->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 <shijie8@gmail.com>");
MODULE_AUTHOR("Mike Lavender");