diff options
author | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-12-18 20:00:52 +0100 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-12-18 20:00:52 +0100 |
commit | f366d3854ec0fec0f9949dac46431598614a956b (patch) | |
tree | d60aa8b796ef2611b0ee28bccb38cca64a1aed2f /drivers/mtd | |
parent | ccec4a4a4f27b22e51ec6a143319db49b7570581 (diff) | |
parent | b422847877e35d6818f65cb359a60f529fe22c4b (diff) |
Merge tag 'spi-nor/for-4.21' of git://git.infradead.org/linux-mtd into mtd/next
Core changes:
- Parse the 4BAIT SFDP section
- Add a bunch of SPI NOR entries to the flash_info table
- Add the concept of SFDP fixups and use it to fix a bug on MX25L25635F
- A bunch of minor cleanups/comestic changes
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/bbt.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/atmel/nand-controller.c | 11 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/qcom_nandc.c | 32 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/cadence-quadspi.c | 19 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 1501 |
5 files changed, 970 insertions, 596 deletions
diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c index 56cde38b92c0..044adf913854 100644 --- a/drivers/mtd/nand/bbt.c +++ b/drivers/mtd/nand/bbt.c @@ -27,7 +27,8 @@ int nanddev_bbt_init(struct nand_device *nand) unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, BITS_PER_LONG); - nand->bbt.cache = kzalloc(nwords, GFP_KERNEL); + nand->bbt.cache = kcalloc(nwords, sizeof(*nand->bbt.cache), + GFP_KERNEL); if (!nand->bbt.cache) return -ENOMEM; diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index dcd3bd73e549..5781fcf6b76c 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2033,8 +2033,7 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc) int ret; nand_np = dev->of_node; - nfc_np = of_find_compatible_node(dev->of_node, NULL, - "atmel,sama5d3-nfc"); + nfc_np = of_get_compatible_child(dev->of_node, "atmel,sama5d3-nfc"); if (!nfc_np) { dev_err(dev, "Could not find device node for sama5d3-nfc\n"); return -ENODEV; @@ -2448,15 +2447,19 @@ static int atmel_nand_controller_probe(struct platform_device *pdev) } if (caps->legacy_of_bindings) { + struct device_node *nfc_node; u32 ale_offs = 21; /* * If we are parsing legacy DT props and the DT contains a * valid NFC node, forward the request to the sama5 logic. */ - if (of_find_compatible_node(pdev->dev.of_node, NULL, - "atmel,sama5d3-nfc")) + nfc_node = of_get_compatible_child(pdev->dev.of_node, + "atmel,sama5d3-nfc"); + if (nfc_node) { caps = &atmel_sama5_nand_caps; + of_node_put(nfc_node); + } /* * Even if the compatible says we are dealing with an diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 6b76fb5c0aed..46c62a31fa46 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -150,15 +150,15 @@ #define NAND_VERSION_MINOR_SHIFT 16 /* NAND OP_CMDs */ -#define PAGE_READ 0x2 -#define PAGE_READ_WITH_ECC 0x3 -#define PAGE_READ_WITH_ECC_SPARE 0x4 -#define PROGRAM_PAGE 0x6 -#define PAGE_PROGRAM_WITH_ECC 0x7 -#define PROGRAM_PAGE_SPARE 0x9 -#define BLOCK_ERASE 0xa -#define FETCH_ID 0xb -#define RESET_DEVICE 0xd +#define OP_PAGE_READ 0x2 +#define OP_PAGE_READ_WITH_ECC 0x3 +#define OP_PAGE_READ_WITH_ECC_SPARE 0x4 +#define OP_PROGRAM_PAGE 0x6 +#define OP_PAGE_PROGRAM_WITH_ECC 0x7 +#define OP_PROGRAM_PAGE_SPARE 0x9 +#define OP_BLOCK_ERASE 0xa +#define OP_FETCH_ID 0xb +#define OP_RESET_DEVICE 0xd /* Default Value for NAND_DEV_CMD_VLD */ #define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ @@ -692,11 +692,11 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) if (read) { if (host->use_ecc) - cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; + cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; else - cmd = PAGE_READ | PAGE_ACC | LAST_PAGE; + cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE; } else { - cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; + cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; } if (host->use_ecc) { @@ -1170,7 +1170,7 @@ static int nandc_param(struct qcom_nand_host *host) * in use. we configure the controller to perform a raw read of 512 * bytes to read onfi params */ - nandc_set_reg(nandc, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE); + nandc_set_reg(nandc, NAND_FLASH_CMD, OP_PAGE_READ | PAGE_ACC | LAST_PAGE); nandc_set_reg(nandc, NAND_ADDR0, 0); nandc_set_reg(nandc, NAND_ADDR1, 0); nandc_set_reg(nandc, NAND_DEV0_CFG0, 0 << CW_PER_PAGE @@ -1224,7 +1224,7 @@ static int erase_block(struct qcom_nand_host *host, int page_addr) struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); nandc_set_reg(nandc, NAND_FLASH_CMD, - BLOCK_ERASE | PAGE_ACC | LAST_PAGE); + OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE); nandc_set_reg(nandc, NAND_ADDR0, page_addr); nandc_set_reg(nandc, NAND_ADDR1, 0); nandc_set_reg(nandc, NAND_DEV0_CFG0, @@ -1255,7 +1255,7 @@ static int read_id(struct qcom_nand_host *host, int column) if (column == -1) return 0; - nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID); + nandc_set_reg(nandc, NAND_FLASH_CMD, OP_FETCH_ID); nandc_set_reg(nandc, NAND_ADDR0, column); nandc_set_reg(nandc, NAND_ADDR1, 0); nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, @@ -1276,7 +1276,7 @@ static int reset(struct qcom_nand_host *host) struct nand_chip *chip = &host->chip; struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE); + nandc_set_reg(nandc, NAND_FLASH_CMD, OP_RESET_DEVICE); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index d846428ef038..04cedd3a2bf6 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -644,9 +644,23 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr, ndelay(cqspi->wr_delay); while (remaining > 0) { + size_t write_words, mod_bytes; + write_bytes = remaining > page_size ? page_size : remaining; - iowrite32_rep(cqspi->ahb_base, txbuf, - DIV_ROUND_UP(write_bytes, 4)); + write_words = write_bytes / 4; + mod_bytes = write_bytes % 4; + /* Write 4 bytes at a time then single bytes. */ + if (write_words) { + iowrite32_rep(cqspi->ahb_base, txbuf, write_words); + txbuf += (write_words * 4); + } + if (mod_bytes) { + unsigned int temp = 0xFFFFFFFF; + + memcpy(&temp, txbuf, mod_bytes); + iowrite32(temp, cqspi->ahb_base); + txbuf += mod_bytes; + } if (!wait_for_completion_timeout(&cqspi->transfer_complete, msecs_to_jiffies(CQSPI_TIMEOUT_MS))) { @@ -655,7 +669,6 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr, goto failwr; } - txbuf += write_bytes; remaining -= write_bytes; if (remaining > 0) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3e54e31889c7..6e13bbd1aaa5 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c * * Copyright (C) 2005, Intec Automation Inc. * Copyright (C) 2014, Freescale Semiconductor, Inc. - * - * This code is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> @@ -42,6 +39,197 @@ #define SPI_NOR_MAX_ID_LEN 6 #define SPI_NOR_MAX_ADDR_WIDTH 4 +struct spi_nor_read_command { + u8 num_mode_clocks; + u8 num_wait_states; + u8 opcode; + enum spi_nor_protocol proto; +}; + +struct spi_nor_pp_command { + u8 opcode; + enum spi_nor_protocol proto; +}; + +enum spi_nor_read_command_index { + SNOR_CMD_READ, + SNOR_CMD_READ_FAST, + SNOR_CMD_READ_1_1_1_DTR, + + /* Dual SPI */ + SNOR_CMD_READ_1_1_2, + SNOR_CMD_READ_1_2_2, + SNOR_CMD_READ_2_2_2, + SNOR_CMD_READ_1_2_2_DTR, + + /* Quad SPI */ + SNOR_CMD_READ_1_1_4, + SNOR_CMD_READ_1_4_4, + SNOR_CMD_READ_4_4_4, + SNOR_CMD_READ_1_4_4_DTR, + + /* Octo SPI */ + SNOR_CMD_READ_1_1_8, + SNOR_CMD_READ_1_8_8, + SNOR_CMD_READ_8_8_8, + SNOR_CMD_READ_1_8_8_DTR, + + SNOR_CMD_READ_MAX +}; + +enum spi_nor_pp_command_index { + SNOR_CMD_PP, + + /* Quad SPI */ + SNOR_CMD_PP_1_1_4, + SNOR_CMD_PP_1_4_4, + SNOR_CMD_PP_4_4_4, + + /* Octo SPI */ + SNOR_CMD_PP_1_1_8, + SNOR_CMD_PP_1_8_8, + SNOR_CMD_PP_8_8_8, + + SNOR_CMD_PP_MAX +}; + +struct spi_nor_flash_parameter { + u64 size; + u32 page_size; + + struct spi_nor_hwcaps hwcaps; + struct spi_nor_read_command reads[SNOR_CMD_READ_MAX]; + struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX]; + + int (*quad_enable)(struct spi_nor *nor); +}; + +struct sfdp_parameter_header { + u8 id_lsb; + u8 minor; + u8 major; + u8 length; /* in double words */ + u8 parameter_table_pointer[3]; /* byte address */ + u8 id_msb; +}; + +#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) +#define SFDP_PARAM_HEADER_PTP(p) \ + (((p)->parameter_table_pointer[2] << 16) | \ + ((p)->parameter_table_pointer[1] << 8) | \ + ((p)->parameter_table_pointer[0] << 0)) + +#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ +#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ +#define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */ + +#define SFDP_SIGNATURE 0x50444653U +#define SFDP_JESD216_MAJOR 1 +#define SFDP_JESD216_MINOR 0 +#define SFDP_JESD216A_MINOR 5 +#define SFDP_JESD216B_MINOR 6 + +struct sfdp_header { + u32 signature; /* Ox50444653U <=> "SFDP" */ + u8 minor; + u8 major; + u8 nph; /* 0-base number of parameter headers */ + u8 unused; + + /* Basic Flash Parameter Table. */ + struct sfdp_parameter_header bfpt_header; +}; + +/* Basic Flash Parameter Table */ + +/* + * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs. + * They are indexed from 1 but C arrays are indexed from 0. + */ +#define BFPT_DWORD(i) ((i) - 1) +#define BFPT_DWORD_MAX 16 + +/* The first version of JESB216 defined only 9 DWORDs. */ +#define BFPT_DWORD_MAX_JESD216 9 + +/* 1st DWORD. */ +#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) +#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) +#define BFPT_DWORD1_DTR BIT(19) +#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) +#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) +#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) + +/* 5th DWORD. */ +#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) +#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) + +/* 11th DWORD. */ +#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 +#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) + +/* 15th DWORD. */ + +/* + * (from JESD216 rev B) + * Quad Enable Requirements (QER): + * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 + * reads based on instruction. DQ3/HOLD# functions are hold during + * instruction phase. + * - 001b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * Writing only one byte to the status register has the side-effect of + * clearing status register 2, including the QE bit. The 100b code is + * used if writing one byte to the status register does not modify + * status register 2. + * - 010b: QE is bit 6 of status register 1. It is set via Write Status with + * one data byte where bit 6 is one. + * [...] + * - 011b: QE is bit 7 of status register 2. It is set via Write status + * register 2 instruction 3Eh with one data byte where bit 7 is one. + * [...] + * The status register 2 is read using instruction 3Fh. + * - 100b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * In contrast to the 001b code, writing one byte to the status + * register does not modify status register 2. + * - 101b: QE is bit 1 of status register 2. Status register 1 is read using + * Read Status instruction 05h. Status register2 is read using + * instruction 35h. QE is set via Writ Status instruction 01h with + * two data bytes where bit 1 of the second byte is one. + * [...] + */ +#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) +#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ +#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ +#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ + +struct sfdp_bfpt { + u32 dwords[BFPT_DWORD_MAX]; +}; + +/** + * struct spi_nor_fixups - SPI NOR fixup hooks + * @post_bfpt: called after the BFPT table has been parsed + * + * Those hooks can be used to tweak the SPI NOR configuration when the SFDP + * table is broken or not available. + */ +struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params); +}; + struct flash_info { char *name; @@ -91,13 +279,14 @@ struct flash_info { #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define USE_CLSR BIT(14) /* use CLSR command */ + /* Part specific fixup hooks. */ + const struct spi_nor_fixups *fixups; + int (*quad_enable)(struct spi_nor *nor); }; #define JEDEC_MFR(info) ((info)->id[0]) -static const struct flash_info *spi_nor_match_id(const char *name); - /* * Read the status register, returning its value in the location * Return the status register value. @@ -159,7 +348,7 @@ static int read_cr(struct spi_nor *nor) * Write status register 1 byte * Returns negative if error occurred. */ -static inline int write_sr(struct spi_nor *nor, u8 val) +static int write_sr(struct spi_nor *nor, u8 val) { nor->cmd_buf[0] = val; return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); @@ -169,7 +358,7 @@ static inline int write_sr(struct spi_nor *nor, u8 val) * Set write enable latch with Write Enable command. * Returns negative if error occurred. */ -static inline int write_enable(struct spi_nor *nor) +static int write_enable(struct spi_nor *nor) { return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); } @@ -177,12 +366,12 @@ static inline int write_enable(struct spi_nor *nor) /* * Send write disable instruction to the chip. */ -static inline int write_disable(struct spi_nor *nor) +static int write_disable(struct spi_nor *nor) { return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0); } -static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) +static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) { return mtd->priv; } @@ -200,7 +389,7 @@ static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) return opcode; } -static inline u8 spi_nor_convert_3to4_read(u8 opcode) +static u8 spi_nor_convert_3to4_read(u8 opcode) { static const u8 spi_nor_3to4_read[][2] = { { SPINOR_OP_READ, SPINOR_OP_READ_4B }, @@ -219,7 +408,7 @@ static inline u8 spi_nor_convert_3to4_read(u8 opcode) ARRAY_SIZE(spi_nor_3to4_read)); } -static inline u8 spi_nor_convert_3to4_program(u8 opcode) +static u8 spi_nor_convert_3to4_program(u8 opcode) { static const u8 spi_nor_3to4_program[][2] = { { SPINOR_OP_PP, SPINOR_OP_PP_4B }, @@ -231,7 +420,7 @@ static inline u8 spi_nor_convert_3to4_program(u8 opcode) ARRAY_SIZE(spi_nor_3to4_program)); } -static inline u8 spi_nor_convert_3to4_erase(u8 opcode) +static u8 spi_nor_convert_3to4_erase(u8 opcode) { static const u8 spi_nor_3to4_erase[][2] = { { SPINOR_OP_BE_4K, SPINOR_OP_BE_4K_4B }, @@ -243,15 +432,14 @@ static inline u8 spi_nor_convert_3to4_erase(u8 opcode) ARRAY_SIZE(spi_nor_3to4_erase)); } -static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, - const struct flash_info *info) +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) { /* Do some manufacturer fixups first */ - switch (JEDEC_MFR(info)) { + switch (JEDEC_MFR(nor->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; + nor->mtd.erasesize = nor->info->sector_size; break; default: @@ -276,17 +464,18 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, } /* Enable/disable 4-byte addressing mode. */ -static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, - int enable) +static int set_4byte(struct spi_nor *nor, bool enable) { int status; bool need_wren = false; u8 cmd; - switch (JEDEC_MFR(info)) { + switch (JEDEC_MFR(nor->info)) { + case SNOR_MFR_ST: case SNOR_MFR_MICRON: /* Some Micron need WREN command; all will accept it */ need_wren = true; + /* fall through */ case SNOR_MFR_MACRONIX: case SNOR_MFR_WINBOND: if (need_wren) @@ -298,7 +487,7 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, write_disable(nor); if (!status && !enable && - JEDEC_MFR(info) == SNOR_MFR_WINBOND) { + JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) { /* * On Winbond W25Q256FV, leaving 4byte mode causes * the Extended Address Register to be set to 1, so all @@ -333,7 +522,7 @@ static int s3an_sr_ready(struct spi_nor *nor) return !!(val & XSR_RDY); } -static inline int spi_nor_sr_ready(struct spi_nor *nor) +static int spi_nor_sr_ready(struct spi_nor *nor) { int sr = read_sr(nor); if (sr < 0) @@ -352,7 +541,7 @@ static inline int spi_nor_sr_ready(struct spi_nor *nor) return !(sr & SR_WIP); } -static inline int spi_nor_fsr_ready(struct spi_nor *nor) +static int spi_nor_fsr_ready(struct spi_nor *nor) { int fsr = read_fsr(nor); if (fsr < 0) @@ -1200,7 +1389,247 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) return ret; } -static int macronix_quad_enable(struct spi_nor *nor); +/* + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. + * Return negative if error occurred. + */ +static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) +{ + int ret; + + write_enable(nor); + + ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2); + if (ret < 0) { + dev_err(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret) { + dev_err(nor->dev, + "timeout while writing configuration register\n"); + return ret; + } + + return 0; +} + +/** + * macronix_quad_enable() - set QE bit in Status Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Status Register. + * + * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int macronix_quad_enable(struct spi_nor *nor) +{ + int ret, val; + + val = read_sr(nor); + if (val < 0) + return val; + if (val & SR_QUAD_EN_MX) + return 0; + + write_enable(nor); + + write_sr(nor, val | SR_QUAD_EN_MX); + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + ret = read_sr(nor); + if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + dev_err(nor->dev, "Macronix Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +/** + * spansion_quad_enable() - set QE bit in Configuraiton Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Configuration Register. + * This function is kept for legacy purpose because it has been used for a + * long time without anybody complaining but it should be considered as + * deprecated and maybe buggy. + * First, this function doesn't care about the previous values of the Status + * and Configuration Registers when it sets the QE bit (bit 1) in the + * Configuration Register: all other bits are cleared, which may have unwanted + * side effects like removing some block protections. + * Secondly, it uses the Read Configuration Register (35h) instruction though + * some very old and few memories don't support this instruction. If a pull-up + * resistor is present on the MISO/IO1 line, we might still be able to pass the + * "read back" test because the QSPI memory doesn't recognize the command, + * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF. + * + * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI + * memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable(struct spi_nor *nor) +{ + u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN}; + int ret; + + ret = write_sr_cr(nor, sr_cr); + if (ret) + return ret; + + /* 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; +} + +/** + * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Configuration Register. + * This function should be used with QSPI memories not supporting the Read + * Configuration Register (35h) instruction. + * + * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI + * memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) +{ + u8 sr_cr[2]; + int ret; + + /* Keep the current value of the Status Register. */ + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, "error while reading status register\n"); + return -EINVAL; + } + sr_cr[0] = ret; + sr_cr[1] = CR_QUAD_EN_SPAN; + + return write_sr_cr(nor, sr_cr); +} + +/** + * spansion_read_cr_quad_enable() - set QE bit in Configuration Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Configuration Register. + * This function should be used with QSPI memories supporting the Read + * Configuration Register (35h) instruction. + * + * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI + * memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_read_cr_quad_enable(struct spi_nor *nor) +{ + struct device *dev = nor->dev; + u8 sr_cr[2]; + int ret; + + /* Check current Quad Enable bit value. */ + ret = read_cr(nor); + if (ret < 0) { + dev_err(dev, "error while reading configuration register\n"); + return -EINVAL; + } + + if (ret & CR_QUAD_EN_SPAN) + return 0; + + sr_cr[1] = ret | CR_QUAD_EN_SPAN; + + /* Keep the current value of the Status Register. */ + ret = read_sr(nor); + if (ret < 0) { + dev_err(dev, "error while reading status register\n"); + return -EINVAL; + } + sr_cr[0] = ret; + + ret = write_sr_cr(nor, sr_cr); + if (ret) + return ret; + + /* 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; +} + +/** + * sr2_bit7_quad_enable() - set QE bit in Status Register 2. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Status Register 2. + * + * This is one of the procedures to set the QE bit described in the SFDP + * (JESD216 rev B) specification but no manufacturer using this procedure has + * been identified yet, hence the name of the function. + * + * Return: 0 on success, -errno otherwise. + */ +static int sr2_bit7_quad_enable(struct spi_nor *nor) +{ + u8 sr2; + int ret; + + /* Check current Quad Enable bit value. */ + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); + if (ret) + return ret; + if (sr2 & SR2_QUAD_EN_BIT7) + return 0; + + /* Update the Quad Enable bit. */ + sr2 |= SR2_QUAD_EN_BIT7; + + write_enable(nor); + + ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1); + if (ret < 0) { + dev_err(nor->dev, "error while writing status register 2\n"); + return -EINVAL; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret < 0) { + dev_err(nor->dev, "timeout while writing status register 2\n"); + return ret; + } + + /* Read back and check it. */ + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); + if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) { + dev_err(nor->dev, "SR2 Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -1252,6 +1681,31 @@ static int macronix_quad_enable(struct spi_nor *nor); .addr_width = 3, \ .flags = SPI_NOR_NO_FR | SPI_S3AN, +static int +mx25l25635_post_bfpt_fixups(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + /* + * MX25L25635F supports 4B opcodes but MX25L25635E does not. + * Unfortunately, Macronix has re-used the same JEDEC ID for both + * variants which prevents us from defining a new entry in the parts + * table. + * We need a way to differentiate MX25L25635E and MX25L25635F, and it + * seems that the F version advertises support for Fast Read 4-4-4 in + * its BFPT table. + */ + if (bfpt->dwords[BFPT_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4) + nor->flags |= SNOR_F_4B_OPCODES; + + return 0; +} + +static struct spi_nor_fixups mx25l25635_fixups = { + .post_bfpt = mx25l25635_post_bfpt_fixups, +}; + /* 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. @@ -1352,12 +1806,19 @@ static const struct flash_info spi_nor_ids[] = { { "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) }, { "is25lq040b", INFO(0x9d4013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "is25lp016d", INFO(0x9d6015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25lp080d", INFO(0x9d6014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "is25lp032", INFO(0x9d6016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ) }, + { "is25lp064", INFO(0x9d6017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, @@ -1380,7 +1841,11 @@ static const struct flash_info spi_nor_ids[] = { { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + .fixups = &mx25l25635_fixups }, { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, @@ -1388,7 +1853,7 @@ static const struct flash_info spi_nor_ids[] = { { "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, - /* Micron */ + /* Micron <--> ST Micro */ { "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, @@ -1404,6 +1869,12 @@ static const struct flash_info spi_nor_ids[] = { { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + /* Micron */ + { + "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, + SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES) + }, + /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, @@ -1531,6 +2002,11 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + { + "w25q128jv", INFO(0xef7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, { "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) }, @@ -1763,248 +2239,6 @@ write_err: return ret; } -/** - * macronix_quad_enable() - set QE bit in Status Register. - * @nor: pointer to a 'struct spi_nor' - * - * Set the Quad Enable (QE) bit in the Status Register. - * - * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories. - * - * Return: 0 on success, -errno otherwise. - */ -static int macronix_quad_enable(struct spi_nor *nor) -{ - int ret, val; - - val = read_sr(nor); - if (val < 0) - return val; - if (val & SR_QUAD_EN_MX) - return 0; - - write_enable(nor); - - write_sr(nor, val | SR_QUAD_EN_MX); - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - ret = read_sr(nor); - if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { - dev_err(nor->dev, "Macronix 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 - * second byte will be written to the configuration register. - * Return negative if error occurred. - */ -static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) -{ - int ret; - - write_enable(nor); - - ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2); - if (ret < 0) { - dev_err(nor->dev, - "error while writing configuration register\n"); - return -EINVAL; - } - - ret = spi_nor_wait_till_ready(nor); - if (ret) { - dev_err(nor->dev, - "timeout while writing configuration register\n"); - return ret; - } - - return 0; -} - -/** - * spansion_quad_enable() - set QE bit in Configuraiton Register. - * @nor: pointer to a 'struct spi_nor' - * - * Set the Quad Enable (QE) bit in the Configuration Register. - * This function is kept for legacy purpose because it has been used for a - * long time without anybody complaining but it should be considered as - * deprecated and maybe buggy. - * First, this function doesn't care about the previous values of the Status - * and Configuration Registers when it sets the QE bit (bit 1) in the - * Configuration Register: all other bits are cleared, which may have unwanted - * side effects like removing some block protections. - * Secondly, it uses the Read Configuration Register (35h) instruction though - * some very old and few memories don't support this instruction. If a pull-up - * resistor is present on the MISO/IO1 line, we might still be able to pass the - * "read back" test because the QSPI memory doesn't recognize the command, - * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF. - * - * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI - * memories. - * - * Return: 0 on success, -errno otherwise. - */ -static int spansion_quad_enable(struct spi_nor *nor) -{ - u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN}; - int ret; - - ret = write_sr_cr(nor, sr_cr); - if (ret) - return ret; - - /* 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; -} - -/** - * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register. - * @nor: pointer to a 'struct spi_nor' - * - * Set the Quad Enable (QE) bit in the Configuration Register. - * This function should be used with QSPI memories not supporting the Read - * Configuration Register (35h) instruction. - * - * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI - * memories. - * - * Return: 0 on success, -errno otherwise. - */ -static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) -{ - u8 sr_cr[2]; - int ret; - - /* Keep the current value of the Status Register. */ - ret = read_sr(nor); - if (ret < 0) { - dev_err(nor->dev, "error while reading status register\n"); - return -EINVAL; - } - sr_cr[0] = ret; - sr_cr[1] = CR_QUAD_EN_SPAN; - - return write_sr_cr(nor, sr_cr); -} - -/** - * spansion_read_cr_quad_enable() - set QE bit in Configuration Register. - * @nor: pointer to a 'struct spi_nor' - * - * Set the Quad Enable (QE) bit in the Configuration Register. - * This function should be used with QSPI memories supporting the Read |