diff options
author | Richard Weinberger <richard@nod.at> | 2020-08-02 21:36:34 +0200 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2020-08-02 21:36:34 +0200 |
commit | cb413909ae849bd2126122fcc11838e905c34951 (patch) | |
tree | cea991e1aaa8795ae51d0d0c2199d023f2429749 /drivers/mtd | |
parent | fbd9b5437b668900f6d8c8e29c8aabf4955189ff (diff) | |
parent | e93a977367b2aefff3c1fb426bbdfc6e2980815f (diff) |
Merge tag 'spi-nor/for-5.9' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux into mtd/next
SPI NOR core changes:
- Disable Quad Mode in spi_nor_restore().
- Don't abort BFPT parsing when QER reserved value is used.
- Add support/update capabilities for few flashes.
- Drop s70fl01gs flash: it does not support RDSR(05h) which
is critical for erase/write.
- Merge the SPIMEM DTR bits in spi-nor/next to avoid conflicts
during the release cycle.
SPI NOR controller drivers changes:
- Move the cadence-quadspi driver to spi-mem. The series was
taken through the SPI tree. Merge it also in spi-nor/next
to avoid conflicts during the release cycle.
- intel-spi:
- Add new PCI IDs.
- Ignore the Write Disable command, the controller doesn't
support it.
- Fix performance regression.
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/spi-nor/controllers/Kconfig | 11 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/controllers/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/controllers/cadence-quadspi.c | 1540 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/controllers/intel-spi-pci.c | 2 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/controllers/intel-spi.c | 13 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/core.c | 57 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/core.h | 10 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/macronix.c | 6 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/micron-st.c | 4 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/sfdp.c | 3 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spansion.c | 4 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/winbond.c | 4 |
12 files changed, 71 insertions, 1584 deletions
diff --git a/drivers/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig index d89a5ea9446a..5c0e0ec2e6d1 100644 --- a/drivers/mtd/spi-nor/controllers/Kconfig +++ b/drivers/mtd/spi-nor/controllers/Kconfig @@ -9,17 +9,6 @@ config SPI_ASPEED_SMC and support for the SPI flash memory controller (SPI) for the host firmware. The implementation only supports SPI NOR. -config SPI_CADENCE_QUADSPI - tristate "Cadence Quad SPI controller" - depends on OF && (ARM || ARM64 || COMPILE_TEST) - help - Enable support for the Cadence Quad SPI Flash controller. - - Cadence QSPI is a specialized controller for connecting an SPI - Flash over 1/2/4-bit wide bus. Enable this option if you have a - device with a Cadence QSPI controller and want to access the - Flash as an MTD device. - config SPI_HISI_SFC tristate "Hisilicon FMC SPI NOR Flash Controller(SFC)" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile index 46e6fbe586e3..e7abba491d98 100644 --- a/drivers/mtd/spi-nor/controllers/Makefile +++ b/drivers/mtd/spi-nor/controllers/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o -obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o diff --git a/drivers/mtd/spi-nor/controllers/cadence-quadspi.c b/drivers/mtd/spi-nor/controllers/cadence-quadspi.c deleted file mode 100644 index 494dcab4aaaa..000000000000 --- a/drivers/mtd/spi-nor/controllers/cadence-quadspi.c +++ /dev/null @@ -1,1540 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for Cadence QSPI Controller - * - * Copyright Altera Corporation (C) 2012-2014. All rights reserved. - */ -#include <linux/clk.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/iopoll.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/spi-nor.h> -#include <linux/of_device.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/reset.h> -#include <linux/sched.h> -#include <linux/spi/spi.h> -#include <linux/timer.h> - -#define CQSPI_NAME "cadence-qspi" -#define CQSPI_MAX_CHIPSELECT 16 - -/* Quirks */ -#define CQSPI_NEEDS_WR_DELAY BIT(0) - -/* Capabilities mask */ -#define CQSPI_BASE_HWCAPS_MASK \ - (SNOR_HWCAPS_READ | SNOR_HWCAPS_READ_FAST | \ - SNOR_HWCAPS_READ_1_1_2 | SNOR_HWCAPS_READ_1_1_4 | \ - SNOR_HWCAPS_PP) - -struct cqspi_st; - -struct cqspi_flash_pdata { - struct spi_nor nor; - struct cqspi_st *cqspi; - u32 clk_rate; - u32 read_delay; - u32 tshsl_ns; - u32 tsd2d_ns; - u32 tchsh_ns; - u32 tslch_ns; - u8 inst_width; - u8 addr_width; - u8 data_width; - u8 cs; - bool registered; - bool use_direct_mode; -}; - -struct cqspi_st { - struct platform_device *pdev; - - struct clk *clk; - unsigned int sclk; - - void __iomem *iobase; - void __iomem *ahb_base; - resource_size_t ahb_size; - struct completion transfer_complete; - struct mutex bus_mutex; - - struct dma_chan *rx_chan; - struct completion rx_dma_complete; - dma_addr_t mmap_phys_base; - - int current_cs; - int current_page_size; - int current_erase_size; - int current_addr_width; - unsigned long master_ref_clk_hz; - bool is_decoded_cs; - u32 fifo_depth; - u32 fifo_width; - bool rclk_en; - u32 trigger_address; - u32 wr_delay; - struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT]; -}; - -struct cqspi_driver_platdata { - u32 hwcaps_mask; - u8 quirks; -}; - -/* Operation timeout value */ -#define CQSPI_TIMEOUT_MS 500 -#define CQSPI_READ_TIMEOUT_MS 10 - -/* Instruction type */ -#define CQSPI_INST_TYPE_SINGLE 0 -#define CQSPI_INST_TYPE_DUAL 1 -#define CQSPI_INST_TYPE_QUAD 2 -#define CQSPI_INST_TYPE_OCTAL 3 - -#define CQSPI_DUMMY_CLKS_PER_BYTE 8 -#define CQSPI_DUMMY_BYTES_MAX 4 -#define CQSPI_DUMMY_CLKS_MAX 31 - -#define CQSPI_STIG_DATA_LEN_MAX 8 - -/* Register map */ -#define CQSPI_REG_CONFIG 0x00 -#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) -#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL BIT(7) -#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) -#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 -#define CQSPI_REG_CONFIG_DMA_MASK BIT(15) -#define CQSPI_REG_CONFIG_BAUD_LSB 19 -#define CQSPI_REG_CONFIG_IDLE_LSB 31 -#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF -#define CQSPI_REG_CONFIG_BAUD_MASK 0xF - -#define CQSPI_REG_RD_INSTR 0x04 -#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0 -#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8 -#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12 -#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16 -#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20 -#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24 -#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3 -#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3 -#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3 -#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F - -#define CQSPI_REG_WR_INSTR 0x08 -#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0 -#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12 -#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16 - -#define CQSPI_REG_DELAY 0x0C -#define CQSPI_REG_DELAY_TSLCH_LSB 0 -#define CQSPI_REG_DELAY_TCHSH_LSB 8 -#define CQSPI_REG_DELAY_TSD2D_LSB 16 -#define CQSPI_REG_DELAY_TSHSL_LSB 24 -#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF -#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF -#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF -#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF - -#define CQSPI_REG_READCAPTURE 0x10 -#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0 -#define CQSPI_REG_READCAPTURE_DELAY_LSB 1 -#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF - -#define CQSPI_REG_SIZE 0x14 -#define CQSPI_REG_SIZE_ADDRESS_LSB 0 -#define CQSPI_REG_SIZE_PAGE_LSB 4 -#define CQSPI_REG_SIZE_BLOCK_LSB 16 -#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF -#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF -#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F - -#define CQSPI_REG_SRAMPARTITION 0x18 -#define CQSPI_REG_INDIRECTTRIGGER 0x1C - -#define CQSPI_REG_DMA 0x20 -#define CQSPI_REG_DMA_SINGLE_LSB 0 -#define CQSPI_REG_DMA_BURST_LSB 8 -#define CQSPI_REG_DMA_SINGLE_MASK 0xFF -#define CQSPI_REG_DMA_BURST_MASK 0xFF - -#define CQSPI_REG_REMAP 0x24 -#define CQSPI_REG_MODE_BIT 0x28 - -#define CQSPI_REG_SDRAMLEVEL 0x2C -#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0 -#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16 -#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF -#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF - -#define CQSPI_REG_IRQSTATUS 0x40 -#define CQSPI_REG_IRQMASK 0x44 - -#define CQSPI_REG_INDIRECTRD 0x60 -#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0) -#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1) -#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5) - -#define CQSPI_REG_INDIRECTRDWATERMARK 0x64 -#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68 -#define CQSPI_REG_INDIRECTRDBYTES 0x6C - -#define CQSPI_REG_CMDCTRL 0x90 -#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0) -#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1) -#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12 -#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15 -#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16 -#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19 -#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20 -#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23 -#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24 -#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7 -#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3 -#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7 - -#define CQSPI_REG_INDIRECTWR 0x70 -#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0) -#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1) -#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5) - -#define CQSPI_REG_INDIRECTWRWATERMARK 0x74 -#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78 -#define CQSPI_REG_INDIRECTWRBYTES 0x7C - -#define CQSPI_REG_CMDADDRESS 0x94 -#define CQSPI_REG_CMDREADDATALOWER 0xA0 -#define CQSPI_REG_CMDREADDATAUPPER 0xA4 -#define CQSPI_REG_CMDWRITEDATALOWER 0xA8 -#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC - -/* Interrupt status bits */ -#define CQSPI_REG_IRQ_MODE_ERR BIT(0) -#define CQSPI_REG_IRQ_UNDERFLOW BIT(1) -#define CQSPI_REG_IRQ_IND_COMP BIT(2) -#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3) -#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4) -#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5) -#define CQSPI_REG_IRQ_WATERMARK BIT(6) -#define CQSPI_REG_IRQ_IND_SRAM_FULL BIT(12) - -#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \ - CQSPI_REG_IRQ_IND_SRAM_FULL | \ - CQSPI_REG_IRQ_IND_COMP) - -#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \ - CQSPI_REG_IRQ_WATERMARK | \ - CQSPI_REG_IRQ_UNDERFLOW) - -#define CQSPI_IRQ_STATUS_MASK 0x1FFFF - -static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr) -{ - u32 val; - - return readl_relaxed_poll_timeout(reg, val, - (((clr ? ~val : val) & mask) == mask), - 10, CQSPI_TIMEOUT_MS * 1000); -} - -static bool cqspi_is_idle(struct cqspi_st *cqspi) -{ - u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); - - return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB); -} - -static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi) -{ - u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL); - - reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; - return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; -} - -static irqreturn_t cqspi_irq_handler(int this_irq, void *dev) -{ - struct cqspi_st *cqspi = dev; - unsigned int irq_status; - - /* Read interrupt status */ - irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS); - - /* Clear interrupt */ - writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS); - - irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR; - - if (irq_status) - complete(&cqspi->transfer_complete); - - return IRQ_HANDLED; -} - -static unsigned int cqspi_calc_rdreg(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - u32 rdreg = 0; - - rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB; - rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB; - rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; - - return rdreg; -} - -static int cqspi_wait_idle(struct cqspi_st *cqspi) -{ - const unsigned int poll_idle_retry = 3; - unsigned int count = 0; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS); - while (1) { - /* - * Read few times in succession to ensure the controller - * is indeed idle, that is, the bit does not transition - * low again. - */ - if (cqspi_is_idle(cqspi)) - count++; - else - count = 0; - - if (count >= poll_idle_retry) - return 0; - - if (time_after(jiffies, timeout)) { - /* Timeout, in busy mode. */ - dev_err(&cqspi->pdev->dev, - "QSPI is still busy after %dms timeout.\n", - CQSPI_TIMEOUT_MS); - return -ETIMEDOUT; - } - - cpu_relax(); - } -} - -static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg) -{ - void __iomem *reg_base = cqspi->iobase; - int ret; - - /* Write the CMDCTRL without start execution. */ - writel(reg, reg_base + CQSPI_REG_CMDCTRL); - /* Start execute */ - reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK; - writel(reg, reg_base + CQSPI_REG_CMDCTRL); - - /* Polling for completion. */ - ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL, - CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1); - if (ret) { - dev_err(&cqspi->pdev->dev, - "Flash command execution timed out.\n"); - return ret; - } - - /* Polling QSPI idle status. */ - return cqspi_wait_idle(cqspi); -} - -static int cqspi_command_read(struct spi_nor *nor, u8 opcode, - u8 *rxbuf, size_t n_rx) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - unsigned int rdreg; - unsigned int reg; - size_t read_len; - int status; - - if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) { - dev_err(nor->dev, - "Invalid input argument, len %zu rxbuf 0x%p\n", - n_rx, rxbuf); - return -EINVAL; - } - - reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; - - rdreg = cqspi_calc_rdreg(nor); - writel(rdreg, reg_base + CQSPI_REG_RD_INSTR); - - reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); - - /* 0 means 1 byte. */ - reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) - << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); - status = cqspi_exec_flash_cmd(cqspi, reg); - if (status) - return status; - - reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER); - - /* Put the read value into rx_buf */ - read_len = (n_rx > 4) ? 4 : n_rx; - memcpy(rxbuf, ®, read_len); - rxbuf += read_len; - - if (n_rx > 4) { - reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER); - - read_len = n_rx - read_len; - memcpy(rxbuf, ®, read_len); - } - - return 0; -} - -static int cqspi_command_write(struct spi_nor *nor, const u8 opcode, - const u8 *txbuf, size_t n_tx) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - unsigned int reg; - unsigned int data; - size_t write_len; - int ret; - - if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) { - dev_err(nor->dev, - "Invalid input argument, cmdlen %zu txbuf 0x%p\n", - n_tx, txbuf); - return -EINVAL; - } - - reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; - if (n_tx) { - reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); - reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) - << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; - data = 0; - write_len = (n_tx > 4) ? 4 : n_tx; - memcpy(&data, txbuf, write_len); - txbuf += write_len; - writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); - - if (n_tx > 4) { - data = 0; - write_len = n_tx - 4; - memcpy(&data, txbuf, write_len); - writel(data, reg_base + CQSPI_REG_CMDWRITEDATAUPPER); - } - } - ret = cqspi_exec_flash_cmd(cqspi, reg); - return ret; -} - -static int cqspi_command_write_addr(struct spi_nor *nor, - const u8 opcode, const unsigned int addr) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - unsigned int reg; - - reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; - reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); - reg |= ((nor->addr_width - 1) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) - << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; - - writel(addr, reg_base + CQSPI_REG_CMDADDRESS); - - return cqspi_exec_flash_cmd(cqspi, reg); -} - -static int cqspi_read_setup(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - unsigned int dummy_clk = 0; - unsigned int reg; - - reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB; - reg |= cqspi_calc_rdreg(nor); - - /* Setup dummy clock cycles */ - dummy_clk = nor->read_dummy; - if (dummy_clk > CQSPI_DUMMY_CLKS_MAX) - dummy_clk = CQSPI_DUMMY_CLKS_MAX; - - if (dummy_clk / 8) { - reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB); - /* Set mode bits high to ensure chip doesn't enter XIP */ - writel(0xFF, reg_base + CQSPI_REG_MODE_BIT); - - /* Need to subtract the mode byte (8 clocks). */ - if (f_pdata->inst_width != CQSPI_INST_TYPE_QUAD) - dummy_clk -= 8; - - if (dummy_clk) - reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK) - << CQSPI_REG_RD_INSTR_DUMMY_LSB; - } - - writel(reg, reg_base + CQSPI_REG_RD_INSTR); - - /* Set address width */ - reg = readl(reg_base + CQSPI_REG_SIZE); - reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; - reg |= (nor->addr_width - 1); - writel(reg, reg_base + CQSPI_REG_SIZE); - return 0; -} - -static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf, - loff_t from_addr, const size_t n_rx) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - void __iomem *ahb_base = cqspi->ahb_base; - unsigned int remaining = n_rx; - unsigned int mod_bytes = n_rx % 4; - unsigned int bytes_to_read = 0; - u8 *rxbuf_end = rxbuf + n_rx; - int ret = 0; - - writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); - writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); - - /* Clear all interrupts. */ - writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); - - writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); - - reinit_completion(&cqspi->transfer_complete); - writel(CQSPI_REG_INDIRECTRD_START_MASK, - reg_base + CQSPI_REG_INDIRECTRD); - - while (remaining > 0) { - if (!wait_for_completion_timeout(&cqspi->transfer_complete, - msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) - ret = -ETIMEDOUT; - - bytes_to_read = cqspi_get_rd_sram_level(cqspi); - - if (ret && bytes_to_read == 0) { - dev_err(nor->dev, "Indirect read timeout, no bytes\n"); - goto failrd; - } - - while (bytes_to_read != 0) { - unsigned int word_remain = round_down(remaining, 4); - - bytes_to_read *= cqspi->fifo_width; - bytes_to_read = bytes_to_read > remaining ? - remaining : bytes_to_read; - bytes_to_read = round_down(bytes_to_read, 4); - /* Read 4 byte word chunks then single bytes */ - if (bytes_to_read) { - ioread32_rep(ahb_base, rxbuf, - (bytes_to_read / 4)); - } else if (!word_remain && mod_bytes) { - unsigned int temp = ioread32(ahb_base); - - bytes_to_read = mod_bytes; - memcpy(rxbuf, &temp, min((unsigned int) - (rxbuf_end - rxbuf), - bytes_to_read)); - } - rxbuf += bytes_to_read; - remaining -= bytes_to_read; - bytes_to_read = cqspi_get_rd_sram_level(cqspi); - } - - if (remaining > 0) - reinit_completion(&cqspi->transfer_complete); - } - - /* Check indirect done status */ - ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD, - CQSPI_REG_INDIRECTRD_DONE_MASK, 0); - if (ret) { - dev_err(nor->dev, - "Indirect read completion error (%i)\n", ret); - goto failrd; - } - - /* Disable interrupt */ - writel(0, reg_base + CQSPI_REG_IRQMASK); - - /* Clear indirect completion status */ - writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD); - - return 0; - -failrd: - /* Disable interrupt */ - writel(0, reg_base + CQSPI_REG_IRQMASK); - - /* Cancel the indirect read */ - writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, - reg_base + CQSPI_REG_INDIRECTRD); - return ret; -} - -static int cqspi_write_setup(struct spi_nor *nor) -{ - unsigned int reg; - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - - /* Set opcode. */ - reg = nor->program_opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB; - writel(reg, reg_base + CQSPI_REG_WR_INSTR); - reg = cqspi_calc_rdreg(nor); - writel(reg, reg_base + CQSPI_REG_RD_INSTR); - - reg = readl(reg_base + CQSPI_REG_SIZE); - reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; - reg |= (nor->addr_width - 1); - writel(reg, reg_base + CQSPI_REG_SIZE); - return 0; -} - -static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr, - const u8 *txbuf, const size_t n_tx) -{ - const unsigned int page_size = nor->page_size; - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - unsigned int remaining = n_tx; - unsigned int write_bytes; - int ret; - - writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); - writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); - - /* Clear all interrupts. */ - writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); - - writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK); - - reinit_completion(&cqspi->transfer_complete); - writel(CQSPI_REG_INDIRECTWR_START_MASK, - reg_base + CQSPI_REG_INDIRECTWR); - /* - * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access - * Controller programming sequence, couple of cycles of - * QSPI_REF_CLK delay is required for the above bit to - * be internally synchronized by the QSPI module. Provide 5 - * cycles of delay. - */ - if (cqspi->wr_delay) - ndelay(cqspi->wr_delay); - - while (remaining > 0) { - size_t write_words, mod_bytes; - - write_bytes = remaining > page_size ? page_size : remaining; - 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))) { - dev_err(nor->dev, "Indirect write timeout\n"); - ret = -ETIMEDOUT; - goto failwr; - } - - remaining -= write_bytes; - - if (remaining > 0) - reinit_completion(&cqspi->transfer_complete); - } - - /* Check indirect done status */ - ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR, - CQSPI_REG_INDIRECTWR_DONE_MASK, 0); - if (ret) { - dev_err(nor->dev, - "Indirect write completion error (%i)\n", ret); - goto failwr; - } - - /* Disable interrupt. */ - writel(0, reg_base + CQSPI_REG_IRQMASK); - - /* Clear indirect completion status */ - writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR); - - cqspi_wait_idle(cqspi); - - return 0; - -failwr: - /* Disable interrupt. */ - writel(0, reg_base + CQSPI_REG_IRQMASK); - - /* Cancel the indirect write */ - writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, - reg_base + CQSPI_REG_INDIRECTWR); - return ret; -} - -static void cqspi_chipselect(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *reg_base = cqspi->iobase; - unsigned int chip_select = f_pdata->cs; - unsigned int reg; - - reg = readl(reg_base + CQSPI_REG_CONFIG); - if (cqspi->is_decoded_cs) { - reg |= CQSPI_REG_CONFIG_DECODE_MASK; - } else { - reg &= ~CQSPI_REG_CONFIG_DECODE_MASK; - - /* Convert CS if without decoder. - * CS0 to 4b'1110 - * CS1 to 4b'1101 - * CS2 to 4b'1011 - * CS3 to 4b'0111 - */ - chip_select = 0xF & ~(1 << chip_select); - } - - reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK - << CQSPI_REG_CONFIG_CHIPSELECT_LSB); - reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK) - << CQSPI_REG_CONFIG_CHIPSELECT_LSB; - writel(reg, reg_base + CQSPI_REG_CONFIG); -} - -static void cqspi_configure_cs_and_sizes(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *iobase = cqspi->iobase; - unsigned int reg; - - /* configure page size and block size. */ - reg = readl(iobase + CQSPI_REG_SIZE); - reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB); - reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB); - reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; - reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB); - reg |= (ilog2(nor->mtd.erasesize) << CQSPI_REG_SIZE_BLOCK_LSB); - reg |= (nor->addr_width - 1); - writel(reg, iobase + CQSPI_REG_SIZE); - - /* configure the chip select */ - cqspi_chipselect(nor); - - /* Store the new configuration of the controller */ - cqspi->current_page_size = nor->page_size; - cqspi->current_erase_size = nor->mtd.erasesize; - cqspi->current_addr_width = nor->addr_width; -} - -static unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz, - const unsigned int ns_val) -{ - unsigned int ticks; - - ticks = ref_clk_hz / 1000; /* kHz */ - ticks = DIV_ROUND_UP(ticks * ns_val, 1000000); - - return ticks; -} - -static void cqspi_delay(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - void __iomem *iobase = cqspi->iobase; - const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz; - unsigned int tshsl, tchsh, tslch, tsd2d; - unsigned int reg; - unsigned int tsclk; - - /* calculate the number of ref ticks for one sclk tick */ - tsclk = DIV_ROUND_UP(ref_clk_hz, cqspi->sclk); - - tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns); - /* this particular value must be at least one sclk */ - if (tshsl < tsclk) - tshsl = tsclk; - - tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns); - tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns); - tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns); - - reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK) - << CQSPI_REG_DELAY_TSHSL_LSB; - reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK) - << CQSPI_REG_DELAY_TCHSH_LSB; - reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK) - << CQSPI_REG_DELAY_TSLCH_LSB; - reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK) - << CQSPI_REG_DELAY_TSD2D_LSB; - writel(reg, iobase + CQSPI_REG_DELAY); -} - -static void cqspi_config_baudrate_div(struct cqspi_st *cqspi) -{ - const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz; - void __iomem *reg_base = cqspi->iobase; - u32 reg, div; - - /* Recalculate the baudrate divisor based on QSPI specification. */ - div = DIV_ROUND_UP(ref_clk_hz, 2 * cqspi->sclk) - 1; - - reg = readl(reg_base + CQSPI_REG_CONFIG); - reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB); - reg |= (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB; - writel(reg, reg_base + CQSPI_REG_CONFIG); -} - -static void cqspi_readdata_capture(struct cqspi_st *cqspi, - const bool bypass, - const unsigned int delay) -{ - void __iomem *reg_base = cqspi->iobase; - unsigned int reg; - - reg = readl(reg_base + CQSPI_REG_READCAPTURE); - - if (bypass) - reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); - else - reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); - - reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK - << CQSPI_REG_READCAPTURE_DELAY_LSB); - - reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK) - << CQSPI_REG_READCAPTURE_DELAY_LSB; - - writel(reg, reg_base + CQSPI_REG_READCAPTURE); -} - -static void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable) -{ - void __iomem *reg_base = cqspi->iobase; - unsigned int reg; - - reg = readl(reg_base + CQSPI_REG_CONFIG); - - if (enable) - reg |= CQSPI_REG_CONFIG_ENABLE_MASK; - else - reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK; - - writel(reg, reg_base + CQSPI_REG_CONFIG); -} - -static void cqspi_configure(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - const unsigned int sclk = f_pdata->clk_rate; - int switch_cs = (cqspi->current_cs != f_pdata->cs); - int switch_ck = (cqspi->sclk != sclk); - - if ((cqspi->current_page_size != nor->page_size) || - (cqspi->current_erase_size != nor->mtd.erasesize) || - (cqspi->current_addr_width != nor->addr_width)) - switch_cs = 1; - - if (switch_cs || switch_ck) - cqspi_controller_enable(cqspi, 0); - - /* Switch chip select. */ - if (switch_cs) { - cqspi->current_cs = f_pdata->cs; - cqspi_configure_cs_and_sizes(nor); - } - - /* Setup baudrate divisor and delays */ - if (switch_ck) { - cqspi->sclk = sclk; - cqspi_config_baudrate_div(cqspi); - cqspi_delay(nor); - cqspi_readdata_capture(cqspi, !cqspi->rclk_en, - f_pdata->read_delay); - } - - if (switch_cs || switch_ck) - cqspi_controller_enable(cqspi, 1); -} - -static int cqspi_set_protocol(struct spi_nor *nor, const int read) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - - f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE; - f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE; - f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; - - if (read) { - switch (nor->read_proto) { - case SNOR_PROTO_1_1_1: - f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; - break; - case SNOR_PROTO_1_1_2: - f_pdata->data_width = CQSPI_INST_TYPE_DUAL; - break; - case SNOR_PROTO_1_1_4: - f_pdata->data_width = CQSPI_INST_TYPE_QUAD; - break; - case SNOR_PROTO_1_1_8: - f_pdata->data_width = CQSPI_INST_TYPE_OCTAL; - break; - default: - return -EINVAL; - } - } - - cqspi_configure(nor); - - return 0; -} - -static ssize_t cqspi_write(struct spi_nor *nor, loff_t to, - size_t len, const u_char *buf) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - int ret; - - ret = cqspi_set_protocol(nor, 0); - if (ret) - return ret; - - ret = cqspi_write_setup(nor); - if (ret) - return ret; - - if (f_pdata->use_direct_mode) { - memcpy_toio(cqspi->ahb_base + to, buf, len); - ret = cqspi_wait_idle(cqspi); - } else { - ret = cqspi_indirect_write_execute(nor, to, buf, len); - } - if (ret) - return ret; - - return len; -} - -static void cqspi_rx_dma_callback(void *param) -{ - struct cqspi_st *cqspi = param; - - complete(&cqspi->rx_dma_complete); -} - -static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf, - loff_t from, size_t len) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; - dma_addr_t dma_src = (dma_addr_t)cqspi->mmap_phys_base + from; - int ret = 0; - struct dma_async_tx_descriptor *tx; - dma_cookie_t cookie; - dma_addr_t dma_dst; - - if (!cqspi->rx_chan || !virt_addr_valid(buf)) { - memcpy_fromio(buf, cqspi->ahb_base + from, len); - return 0; - } - - dma_dst = dma_map_single(nor->dev, buf, len, DMA_FROM_DEVICE); - if (dma_mapping_error(nor->dev, dma_dst)) { - dev_err(nor->dev, "dma mapping failed\n"); - return -ENOMEM; - } - tx = dmaengine_prep_dma_memcpy(cqspi->rx_chan, dma_dst, dma_src, - len, flags); - if (!tx) { - dev_err(nor->dev, "device_prep_dma_memcpy error\n"); - ret = -EIO; - goto err_unmap; - } - - tx->callback = cqspi_rx_dma_callback; - tx->callback_param = cqspi; - cookie = tx->tx_submit(tx); - reinit_completion(&cqspi->rx_dma_complete); - - ret = dma_submit_error(cookie); - if (ret) { - dev_err(nor->dev, "dma_submit_error %d\n", cookie); - ret = -EIO; - goto err_unmap; - } - - dma_async_issue_pending(cqspi->rx_chan); - if (!wait_for_completion_timeout(&cqspi->rx_dma_complete, - msecs_to_jiffies(len))) { - dmaengine_terminate_sync(cqspi->rx_chan); - dev_err(nor->dev, "DMA wait_for_completion_timeout\n"); - ret = -ETIMEDOUT; - goto err_unmap; - } - -err_unmap: - dma_unmap_single(nor->dev, dma_dst, len, DMA_FROM_DEVICE); - - return ret; -} - -static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, - size_t len, u_char *buf) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - int ret; - - ret = cqspi_set_protocol(nor, 1); - if (ret) - return ret; - - ret = cqspi_read_setup(nor); - if (ret) - return ret; - - if (f_pdata->use_direct_mode) - ret = cqspi_direct_read_execute(nor, buf, from, len); - else - ret = cqspi_indirect_read_execute(nor, buf, from, len); - if (ret) - return ret; - - return len; -} - -static int cqspi_erase(struct spi_nor *nor, loff_t offs) -{ - int ret; - - ret = cqspi_set_protocol(nor, 0); - if (ret) - return ret; - - /* Send write enable, then erase commands. */ - ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREN, NULL, 0); - if (ret) - return ret; - - /* Set up command buffer. */ - ret = cqspi_command_write_addr(nor, nor->erase_opcode, offs); - if (ret) - return ret; - - return 0; -} - -static int cqspi_prep(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - - mutex_lock(&cqspi->bus_mutex); - - return 0; -} - -static void cqspi_unprep(struct spi_nor *nor) -{ - struct cqspi_flash_pdata *f_pdata = nor->priv; - struct cqspi_st *cqspi = f_pdata->cqspi; - - mutex_unlock(&cqspi->bus_mutex); -} - -static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len) -{ - int ret; - - ret = cqspi_set_protocol(nor, 0); - if (!ret) - ret = cqspi_command_read(nor, opcode, buf, len); - - return ret; -} - -static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, - size_t len) -{ - int ret; - - ret = cqspi_set_protocol(nor, 0); - if (!ret) - ret = cqspi_command_write(nor, opcode, buf, len); - - return ret; -} - -static int cqspi_of_get_flash_pdata(struct platform_device *pdev, - struct cqspi_flash_pdata *f_pdata, - struct device_node *np) -{ - if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) { - dev_err(&pdev->dev, "couldn't determine read-delay\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) { - dev_err(&pdev->dev, "couldn't determine tshsl-ns\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) { - dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) { - dev_err(&pdev->dev, "couldn't determine tchsh-ns\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) { - dev_err(&pdev->dev, "couldn't determine tslch-ns\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) { - dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n"); - return -ENXIO; - } - - return 0; -} - -static int cqspi_of_get_pdata(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct cqspi_st *cqspi = platform_get_drvdata(pdev); - - cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs"); - - if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { - dev_err(&pdev->dev, "couldn't determine fifo-depth\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) { - dev_err(&pdev->dev, "couldn't determine fifo-width\n"); - return -ENXIO; - } - - if (of_property_read_u32(np, "cdns,trigger-address", - &cqspi->trigger_address)) { - dev_err(&pdev->dev, "couldn't determine trigger-address\n"); - return -ENXIO; - } - - cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en"); - - return 0; -} - -static void cqspi_controller_init(struct cqspi_st *cqspi) -{ - u32 reg; - - cqspi_controller_enable(cqspi, 0); - - /* Configure the remap address register, no remap */ - writel(0, cqspi->iobase + CQSPI_REG_REMAP); - - /* Disable all interrupts. */ - writel(0, cqspi->iobase + CQSPI_REG_IRQMASK); - - /* Configure the SRAM split to 1:1 . */ - writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION); - - /* Load indirect trigger address. */ - writel(cqspi->trigger_address, - cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER); - - /* Program read watermark -- 1/2 of the FIFO. */ - writel(cqspi->fifo_depth * cqspi->fifo_width / 2, - cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK); - /* Program write watermark -- 1/8 of the FIFO. */ - writel(cqspi->fifo_depth * cqspi->fifo_width / 8, - cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK); - - /* Enable Direct Access Controller */ - reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); - reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL; - writel(reg, cqspi->iobase + CQSPI_REG_CONFIG); - - cqspi_controller_enable(cqspi, 1); -} - -static void cqspi_request_mmap_dma(struct cqspi_st *cqspi) -{ - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_MEMCPY, mask); - - cqspi->rx_chan = dma_request_chan_by_mask(&mask); - if (IS_ERR(cqspi->rx_chan)) { - dev_err(&cqspi->pdev->dev, "No Rx DMA available\n"); - cqspi->rx_chan = NULL; - } - init_completion(&cqspi->rx_dma_complete); -} - -static const struct spi_nor_controller_ops cqspi_controller_ops = { - .prepare = cqspi_prep, - .unprepare = cqspi_unprep, - .read_reg = cqspi_read_reg, - .write_reg = cqspi_write_reg, - .read = cqspi_read, - .write = cqspi_write, - .erase = cqspi_erase, -}; - -static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np) -{ - struct platform_device *pdev = cqspi->pdev; - struct device *dev = &pdev->dev; - const struct cqspi_driver_platdata *ddata; - struct spi_nor_hwcaps hwcaps; - struct cqspi_flash_pdata *f_pdata; - struct spi_nor *nor; - struct mtd_info *mtd; - unsigned int cs; - int i, ret; - - ddata = of_device_get_match_data(dev); - if (!ddata) { - dev_err(dev, "Couldn't find driver data\n"); - return -EINVAL; - } - hwcaps.mask = ddata->hwcaps_mask; - - /* Get flash device data */ - for_each_available_child_of_node(dev->of_node, np) { - ret = of_property_read_u32(np, "reg", &cs); - if (ret) { - dev_err(dev, "Couldn't determine chip select.\n"); - goto err; - } - - if (cs >= CQSPI_MAX_CHIPSELECT) { - ret = -EINVAL; - dev_err(dev, "Chip select %d out of range.\n", cs); - goto err; - } - - f_pdata = &cqspi->f_pdata[cs]; - f_pdata->cqspi = cqspi; - f_pdata->cs = cs; - - ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np); - if (ret) - goto err; - - nor = &f_pdata->nor; - mtd = &nor->mtd; - - mtd->priv = nor; - - nor->dev = dev; - spi_nor_set_flash_node(nor, np); - nor->priv = f_pdata; - nor->controller_ops = &cqspi_controller_ops; - - mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d", - dev_name(dev), cs); - if (!mtd->name) { - ret = -ENOMEM; - goto err; - } - - ret = spi_nor_scan(nor, NULL, &hwcaps); - if (ret) - goto err; - - ret = mtd_device_register(mtd, NULL, 0); - if (ret) - goto err; - - f_pdata->registered = true; - - if (mtd->size <= cqspi->ahb_size) { - f_pdata->use_direct_mode = true; - dev_dbg(nor->dev, "using direct mode for %s\n", - mtd->name); - - if (!cqspi->rx_chan) - cqspi_request_mmap_dma(cqspi); - } - } - - return 0; - -err: - for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++) - if (cqspi->f_pdata[i].registered) - mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd); - return ret; -} - -static int cqspi_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct cqspi_st *cqspi; - struct resource *res; - struct resource *res_ahb; - struct reset_control *rstc, *rstc_ocp; - const struct cqspi_driver_platdata *ddata; - int ret; - int irq; - - cqspi = devm_kzalloc(dev, sizeof(*cqspi), GFP_KERNEL); - if (!cqspi) - return -ENOMEM; - - mutex_init(&cqspi->bus_mutex); - cqspi->pdev = pdev; - platform_set_drvdata(pdev, cqspi); - - /* Obtain configuration from OF. */ - ret = cqspi_of_get_pdata(pdev); - if (ret) { - dev_err(dev, "Cannot get mandatory OF data.\n"); - return -ENODEV; - } - - /* Obtain QSPI clock. */ - cqspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(cqspi->clk)) { - dev_err(dev, "Cannot claim QSPI clock.\n"); - return PTR_ERR(cqspi->clk); - } - - /* Obtain and remap controller address. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cqspi->iobase = devm_ioremap_resource(dev, res); - if (IS_ERR(cqspi->iobase)) { - dev_err(dev, "Cannot remap controller address.\n"); - return PTR_ERR(cqspi->iobase); - } - - /* Obtain and remap AHB address. */ - res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1); - cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb); - if (IS_ERR(cqspi->ahb_base)) { - dev_err(dev, "Cannot remap AHB address.\n"); - return PTR_ERR(cqspi->ahb_base); - } - cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start; - cqspi->ahb_size = resource_size(res_ahb); - - init_completion(&cqspi->transfer_complete); - - /* Obtain IRQ line. */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; - - pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); - return ret; - } - - ret = clk_prepare_enable(cqspi->clk); - if (ret) { - dev_err(dev, "Cannot enable QSPI clock.\n"); - goto probe_clk_failed; - } - - /* Obtain QSPI reset control */ - rstc = devm_reset_control_get_optional_exclusive(dev, "qspi"); - if (IS_ERR(rstc)) { - dev_err(dev, "Cannot get QSPI reset.\n"); - return PTR_ERR(rstc); - } - - rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp"); - if (IS_ERR(rstc_ocp)) { - dev_err(dev, "Cannot get QSPI OCP reset.\n"); - return PTR_ERR(rstc_ocp); - } - - reset_control_assert(rstc); - reset_control_deassert(rstc); - - reset_control_assert(rstc_ocp); - reset_control_deassert(rstc_ocp); - - cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); - ddata = of_device_get_match_data(dev); - if (ddata && (ddata->quirks & CQSPI_NEEDS_WR_DELAY)) - cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC, - cqspi->master_ref_clk_hz); - - ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0, - pdev->name, cqspi); - if (ret) { - dev_err(dev, "Cannot request IRQ.\n"); - goto probe_irq_failed; - } - - cqspi_wait_idle(cqspi); - cqspi_controller_init(cqspi); - cqspi->current_cs = -1; - cqspi->sclk = 0; - - ret = cqspi_setup_flash(cqspi, np); - if (ret) { - dev_err(dev, "Cadence QSPI NOR probe failed %d\n", ret); - goto probe_setup_failed; - } - - return ret; -probe_setup_failed: - cqspi_controller_enable(cqspi, 0); -probe_irq_failed: - clk_disable_unprepare(cqspi->clk); -probe_clk_failed: - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - return ret; -} - -static int cqspi_remove(struct platform_device *pdev) -{ - struct cqspi_st *cqspi = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++) - if (cqspi->f_pdata[i].registered) - mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd); - - cqspi_controller_enable(cqspi, 0); - - if (cqspi->rx_chan) - dma_release_channel(cqspi->rx_chan); - - clk_disable_unprepare(cqspi->clk); - - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int cqspi_suspend(struct device *dev) -{ - struct cqspi_st *cqspi = dev_get_drvdata(dev); - - cqspi_controller_enable(cqspi, 0); - return 0; -} - -static int cqspi_resume(struct device *dev) -{ - struct cqspi_st *cqspi = dev_get_drvdata(dev); - - cqspi_controller_enable(cqspi, 1); - return 0; -} - -static const struct dev_pm_ops cqspi__dev_pm_ops = { - .suspend = cqspi_suspend, - .resume = cqspi_resume, -}; - -#define CQSPI_DEV_PM_OPS (&cqspi__dev_pm_ops) -#else -#define CQSPI_DEV_PM_OPS NULL -#endif - -static const struct cqspi_driver_platdata cdns_qspi = { - .hwcaps_mask = CQSPI_BASE_HWCAPS_MASK, -}; - -static const struct cqspi_driver_platdata k2g_qspi = { - .hwcaps_mask = CQSPI_BASE_HWCAPS_MASK, - .quirks = CQSPI_NEEDS_WR_DELAY, -}; - -static const struct cqspi_driver_platdata am654_ospi = { - .hwcaps_mask = CQSPI_BASE_HWCAPS_MASK | SNOR_HWCAPS_READ_1_1_8, - .quirks = CQSPI_NEEDS_WR_DELAY, -}; - -static const struct of_device_id cqspi_dt_ids[] = { - { - .compatible = "cdns,qspi-nor", - .data = &cdns_qspi, - }, - { - .compatible = "ti,k2g-qspi", - .data = &k2g_qspi, - }, - { - .compatible = "ti,am654-ospi", - .data = &am654_ospi, - }, - { /* end of table */ } -}; - -MODULE_DEVICE_TABLE(of, cqspi_dt_ids); - -static struct platform_driver cqspi_platform_driver = { - .probe = cqspi_probe, - .remove = cqspi_remove, - .driver = { - .name = CQSPI_NAME, - .pm = CQSPI_DEV_PM_OPS, - .of_match_table = cqspi_dt_ids, - }, -}; - -module_platform_driver(cqspi_platform_driver); - -MODULE_DESCRIPTION("Cadence QSPI Controller Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" CQSPI_NAME); -MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>"); -MODULE_AUTHOR("Graham Moore <grmoore@opensource.altera.com>"); diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c index 81329f680bec..c72aa1ab71ad 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c @@ -68,7 +68,9 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c index 61d2a0ad2131..b54a56a68100 100644 --- a/drivers/mtd/spi-nor/controllers/intel-spi.c +++ b/drivers/mtd/spi-nor/controllers/intel-spi.c @@ -292,7 +292,7 @@ static int intel_spi_wait_hw_busy(struct intel_spi *ispi) u32 val; return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, - !(val & HSFSTS_CTL_SCIP), 40, + !(val & HSFSTS_CTL_SCIP), 0, INTEL_SPI_TIMEOUT * 1000); } @@ -301,7 +301,7 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi) u32 val; return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, - !(val & SSFSTS_CTL_SCIP), 40, + !(val & SSFSTS_CTL_SCIP), 0, INTEL_SPI_TIMEOUT * 1000); } @@ -612,6 +612,15 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, return 0; } + /* + * We hope that HW sequencer will do the right thing automatically and + * with the SW sequencer we cannot use preopcode anyway, so just ignore + * the Write Disable operation and pretend it was completed + * successfully. + */ + if (opcode == SPINOR_OP_WRDI) + return 0; + writel(0, ispi->base + FADDR); /* Write the value beforehand */ diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0369d98b2d12..65eff4ce6ab1 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1907,15 +1907,16 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) } /** - * spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status - * Register 1. + * spi_nor_sr1_bit6_quad_enable() - Set/Unset the Quad Enable BIT(6) in the + * Status Register 1. * @nor: pointer to a 'struct spi_nor' + * @enable: true to enable Quad mode, false to disable Quad mode. * * Bit 6 of the Status Register 1 is the QE bit for Macronix like QSPI memories. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor) +int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable) { int ret; @@ -1923,45 +1924,56 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor) if (ret) return ret; - if (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6) + if ((enable && (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)) || + (!enable && !(nor->bouncebuf[0] & SR1_QUAD_EN_BIT6))) return 0; - nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6; + if (enable) + nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6; + else + nor->bouncebuf[0] &= ~SR1_QUAD_EN_BIT6; return spi_nor_write_sr1_and_check(nor, nor->bouncebuf[0]); } /** - * spi_nor_sr2_bit1_quad_enable() - set the Quad Enable BIT(1) in the Status - * Register 2. + * spi_nor_sr2_bit1_quad_enable() - set/unset the Quad Enable BIT(1) in the + * Status Register 2. * @nor: pointer to a 'struct spi_nor'. + * @enable: true to enable Quad mode, false to disable Quad mode. * * Bit 1 of the Status Register 2 is the QE bit for Spansion like QSPI memories. * * Return: 0 on success, -errno otherwise. */ -int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor) +int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable) { int ret; if (nor->flags & SNOR_F_NO_READ_CR) - return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1); + return spi_nor_write_16bit_cr_and_check(nor, + enable ? SR2_QUAD_EN_BIT1 : 0); ret = spi_nor_read_cr(nor, nor->bouncebuf); if (ret) return ret; - if (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1) + if ((enable && (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)) || + (!enable && !(nor->bouncebuf[0] & SR2_QUAD_EN_BIT1))) return 0; - nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1; + if (enable) + nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1; + else + nor->bouncebuf[0] &= ~SR2_QUAD_EN_BIT1; return spi_nor_write_16bit_cr_and_check(nor, nor->bouncebuf[0]); } /** - * spi_nor_sr2_bit7_quad_enable() - set QE bit in Status Register 2. + * spi_nor_sr2_bit7_quad_enable() - set/unset QE bit in Status Register 2. * @nor: pointer to a 'struct spi_nor' + * @enable: true to enable Quad mode, false to disable Quad mode. * * Set the Quad Enable (QE) bit in the Status Register 2. * @@ -1971,7 +1983,7 @@ int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor) +int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable) { u8 *sr2 = nor->bouncebuf; int ret; @@ -1981,11 +1993,15 @@ int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor) ret = spi_nor_read_sr2(nor, sr2); if (ret) return ret; - if (*sr2 & SR2_QUAD_EN_BIT7) + if ((enable && (*sr2 & SR2_QUAD_EN_BIT7)) || + (!enable && !(*sr2 & SR2_QUAD_EN_BIT7))) return 0; /* Update the Quad Enable bit. */ - *sr2 |= SR2_QUAD_EN_BIT7; + if (enable) + *sr2 |= SR2_QUAD_EN_BIT7; + else + *sr2 &= ~SR2_QUAD_EN_BIT7; ret = spi_nor_write_sr2(nor, sr2); if (ret) @@ -2898,12 +2914,13 @@ static int spi_nor_init_params(struct spi_nor *nor) } /** - * spi_nor_quad_enable() - enable Quad I/O if needed. + * spi_nor_quad_enable() - enable/disable Quad I/O if needed. * @nor: pointer to a 'struct spi_nor' + * @enable: true to enable Quad mode. false to disable Quad mode. * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_quad_enable(struct spi_nor *nor) +static int spi_nor_quad_enable(struct spi_nor *nor, bool enable) { if (!nor->params->quad_enable) return 0; @@ -2912,7 +2929,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor) spi_nor_get_protocol_width(nor->write_proto) == 4)) return 0; - return nor->params->quad_enable(nor); + return nor->params->quad_enable(nor, enable); } /** @@ -2936,7 +2953,7 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - err = spi_nor_quad_enable(nor); + err = spi_nor_quad_enable(nor, true); if (err) { dev_dbg(nor->dev, "quad mode not supported\n"); return err; @@ -2983,6 +3000,8 @@ void spi_nor_restore(struct spi_nor *nor) if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && nor->flags & SNOR_F_BROKEN_RESET) nor->params->set_4byte_addr_mode(nor, false); + + spi_nor_quad_enable(nor, false); } EXPORT_SYMBOL_GPL(spi_nor_restore); diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 6f2f6b27173f..95aa32f3ceb1 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -198,7 +198,7 @@ struct spi_nor_locking_ops { * higher index in the array, the higher priority. * @erase_map: the erase map parsed from the SFDP Sector Map Parameter * Table. - * @quad_enable: enables SPI NOR quad mode. + * @quad_enable: enables/disables SPI NOR Quad mode. * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode. * @convert_addr: converts an absolute address into something the flash * will understand. Particularly useful when pagesize is @@ -219,7 +219,7 @@ struct spi_nor_flash_parameter { struct spi_nor_erase_map erase_map; - int (*quad_enable)(struct spi_nor *nor); + int (*quad_enable)(struct spi_nor *nor, bool enable); int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable); u32 (*convert_addr)(struct spi_nor *nor, u32 addr); int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps); @@ -406,9 +406,9 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear); int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_lock_and_prep(struct spi_nor *nor); void spi_nor_unlock_and_unprep(struct spi_nor *nor); -int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor); -int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor); -int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor); +int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable); +int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable); +int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable); int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr); ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 96735d83c77c..f97f3d127575 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -52,6 +52,9 @@ static const struct flash_info macronix_parts[] = { { "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) }, + { "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, { "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, @@ -84,6 +87,9 @@ static const struct flash_info macronix_parts[] = { SPI_NOR_QUAD_READ) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, + { "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, }; static void macronix_default_init(struct spi_nor *nor) diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 3dca5b9af3b6..ef3695080710 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -71,8 +71,8 @@ static const struct flash_info st_parts[] = { 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) }, + SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 55c0c508464b..e2a43d39eb5f 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -598,7 +598,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, break; default: - return -EINVAL; + dev_dbg(nor->dev, "BFPT QER reserved value used\n"); + break; } /* Stop here if not JESD216 rev C or later. */ diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index e550cd5c9d3a..8429b4af999a 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -64,7 +64,6 @@ static const struct flash_info spansion_parts[] = { { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) .fixups = &s25fs_s_fixups, }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, @@ -84,7 +83,8 @@ static const struct flash_info spansion_parts[] = { 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) }, + { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "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) }, diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 5062af10f138..6dcde15fb1aa 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -64,10 +64,12 @@ static const struct flash_info winbond_parts[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "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) }, + { "w25q64jvm", INFO(0xef7017, 0, 64 * 1024, 128, SECT_4K) }, { "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) }, |