From 56c6855c81c8a6828b5d65aa974cd50f4b67760c Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 5 Apr 2018 14:12:49 -0500 Subject: [PATCH 01/15] mtd: spi-nor: Add Micron MT25QU02 support Add support for a new Micron 2Gb Flash memory part. Datasheet is available: mt25q_qlkt_l_02g_cbb_0.pdf Testing was done on a Stratix10 SoCFPGA Development Kit. Reported-by: Sujith Chidurala Tested-by: Paul Kim Signed-off-by: Thor Thayer Acked-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 5bfa36e95f35..8b459766a4ca 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1087,6 +1087,7 @@ static const struct flash_info spi_nor_ids[] = { { "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 | NO_CHIP_ERASE) }, { "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) }, /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, From c7aa1b77f96f3549ac71ac3eb631c8e47536bcf6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 7 Apr 2018 15:01:05 +0200 Subject: [PATCH 02/15] mtd: spi-nor: add support for ISSI is25lp256 Add support for ISSI is25lp256 spi nor flash. Signed-off-by: Marek Vasut Cc: Angelo Dureghello Cc: Boris Brezillon Cc: Cyrille Pitchen Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 8b459766a4ca..cded32974ed1 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1049,6 +1049,8 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_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) }, /* Macronix */ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, From ffa639e069fb55a150a2f14af6762b2c429e6d50 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 10 Apr 2018 13:49:10 +0530 Subject: [PATCH 03/15] mtd: spi-nor: cadence-quadspi: Add DMA support for direct mode reads Add support to use DMA over memory mapped reads in direct mode. This helps in reducing CPU usage from ~100% to ~10% when reading data from flash. For non-DMA'able/vmalloc'd buffers, driver just falls back to CPU based memcpy. Signed-off-by: Vignesh R Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/cadence-quadspi.c | 96 ++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 4b8e9183489a..2f3a4d4232b3 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -73,6 +75,10 @@ struct cqspi_st { 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; @@ -915,11 +921,75 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to, 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_DEV_TO_MEM); + 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); + ret = wait_for_completion_timeout(&cqspi->rx_dma_complete, + msecs_to_jiffies(len)); + if (ret <= 0) { + 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_DEV_TO_MEM); + + return 0; +} + 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; - struct cqspi_st *cqspi = f_pdata->cqspi; int ret; ret = cqspi_set_protocol(nor, 1); @@ -931,7 +1001,7 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, return ret; if (f_pdata->use_direct_mode) - memcpy_fromio(buf, cqspi->ahb_base + from, len); + ret = cqspi_direct_read_execute(nor, buf, from, len); else ret = cqspi_indirect_read_execute(nor, buf, from, len); if (ret) @@ -1100,6 +1170,21 @@ static void cqspi_controller_init(struct cqspi_st *cqspi) 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 int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np) { const struct spi_nor_hwcaps hwcaps = { @@ -1177,6 +1262,9 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np) 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); } } @@ -1237,6 +1325,7 @@ static int cqspi_probe(struct platform_device *pdev) 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); @@ -1307,6 +1396,9 @@ static int cqspi_remove(struct platform_device *pdev) 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); From 640702490d133cc91dec823ac7ef0f1e44eee447 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 10 Apr 2018 17:01:06 -0300 Subject: [PATCH 04/15] mtd: spi-nor: hisi: Avoid generic function names Using generic names such as get_if_type() is frowned upon: it suggests a core function (which is not), and then it makes code navigation harder. Given drivers are often used as starting point to write other drivers, generic names tend to spread like the flu. Cure the problem. Signed-off-by: Ezequiel Garcia Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/hisi-sfc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c index 04f9fb5cd9b6..dea7b0c4b339 100644 --- a/drivers/mtd/spi-nor/hisi-sfc.c +++ b/drivers/mtd/spi-nor/hisi-sfc.c @@ -112,7 +112,7 @@ struct hifmc_host { u32 num_chip; }; -static inline int wait_op_finish(struct hifmc_host *host) +static inline int hisi_spi_nor_wait_op_finish(struct hifmc_host *host) { u32 reg; @@ -120,7 +120,7 @@ static inline int wait_op_finish(struct hifmc_host *host) (reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT); } -static int get_if_type(enum spi_nor_protocol proto) +static int hisi_spi_nor_get_if_type(enum spi_nor_protocol proto) { enum hifmc_iftype if_type; @@ -208,7 +208,7 @@ static int hisi_spi_nor_op_reg(struct spi_nor *nor, reg = FMC_OP_CMD1_EN | FMC_OP_REG_OP_START | optype; writel(reg, host->regbase + FMC_OP); - return wait_op_finish(host); + return hisi_spi_nor_wait_op_finish(host); } static int hisi_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, @@ -259,9 +259,9 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off, reg = OP_CFG_FM_CS(priv->chipselect); if (op_type == FMC_OP_READ) - if_type = get_if_type(nor->read_proto); + if_type = hisi_spi_nor_get_if_type(nor->read_proto); else - if_type = get_if_type(nor->write_proto); + if_type = hisi_spi_nor_get_if_type(nor->write_proto); reg |= OP_CFG_MEM_IF_TYPE(if_type); if (op_type == FMC_OP_READ) reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3); @@ -274,7 +274,7 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off, : OP_CTRL_WR_OPCODE(nor->program_opcode); writel(reg, host->regbase + FMC_OP_DMA); - return wait_op_finish(host); + return hisi_spi_nor_wait_op_finish(host); } static ssize_t hisi_spi_nor_read(struct spi_nor *nor, loff_t from, size_t len, From ce5013ff3bec05cf2a8a05c75fcd520d9914d92b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 18 Apr 2018 22:25:32 +0200 Subject: [PATCH 05/15] mtd: spi-nor: Add support for XM25QH64A and XM25QH128A These devices are produced by Wuhan Xinxin Semiconductor Manufacturing Corp. (XMC) and found on some routers from Chinese manufactures. The data sheets can be found here: http://www.xmcwh.com/Uploads/2018-03-01/5a9799e4cb355.pdf http://www.xmcwh.com/Uploads/2018-02-05/5a77e6dbe968b.pdf Signed-off-by: Hauke Mehrtens Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index cded32974ed1..9363f299e4ee 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1233,6 +1233,10 @@ static const struct flash_info spi_nor_ids[] = { { "3S400AN", S3AN_INFO(0x1f2400, 256, 264) }, { "3S700AN", S3AN_INFO(0x1f2500, 512, 264) }, { "3S1400AN", S3AN_INFO(0x1f2600, 512, 528) }, + + /* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */ + { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { }, }; From f134fbbb4ff813dd227c9ce40b5c0b2078a77b07 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 21 Apr 2018 08:54:40 +1000 Subject: [PATCH 06/15] mtd: spi-nor: clear Winbond Extended Address Reg on switch to 3-byte addressing. Winbond spi-nor flash 32MB and larger have an 'Extended Address Register' as one option for addressing beyond 16MB (Macronix has the same concept, Spansion has EXTADD bits in the Bank Address Register). According to section 8.2.7 Write Extended Address Register (C5h) of the Winbond W25Q256FV data sheet (256M-BIT SPI flash) The Extended Address Register is only effective when the device is in the 3-Byte Address Mode. When the device operates in the 4-Byte Address Mode (ADS=1), any command with address input of A31-A24 will replace the Extended Address Register values. It is recommended to check and update the Extended Address Register if necessary when the device is switched from 4-Byte to 3-Byte Address Mode. So the documentation suggests clearing the EAR after switching to 3-byte mode. Experimentation shows that the EAR is *always* one after the switch to 3-byte mode, so clearing the EAR is mandatory at shutdown for a subsequent 3-byte-addressed reboot to work. Note that some SOCs (e.g. MT7621) do not assert a reset line at normal reboot, so we cannot rely on hardware reset. The MT7621 does assert a reset line at watchdog-reset. Acked-by: Marek Vasut Signed-off-by: NeilBrown Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 14 ++++++++++++++ include/linux/mtd/spi-nor.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 9363f299e4ee..494b7a269872 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -284,6 +284,20 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, if (need_wren) write_disable(nor); + if (!status && !enable && + JEDEC_MFR(info) == SNOR_MFR_WINBOND) { + /* + * On Winbond W25Q256FV, leaving 4byte mode causes + * the Extended Address Register to be set to 1, so all + * 3-byte-address reads come from the second 16M. + * We must clear the register to enable normal behavior. + */ + write_enable(nor); + nor->cmd_buf[0] = 0; + nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1); + write_disable(nor); + } + return status; default: /* Spansion style */ diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index de36969eb359..e60da0d34cc1 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -62,6 +62,8 @@ #define SPINOR_OP_RDCR 0x35 /* Read configuration register */ #define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ #define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */ +#define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */ +#define SPINOR_OP_WREAR 0xc5 /* Write Extended Address Register */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */ From c7d6a82d90e193b1e4daba957e3908f26306d491 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 5 Feb 2018 14:32:59 +0300 Subject: [PATCH 07/15] mtd: spi-nor: intel-spi: Fix atomic sequence handling On many older systems using SW sequencer the PREOP_OPTYPE register contains two preopcodes as following: PREOP_OPTYPE=0xf2785006 The last two bytes are the opcodes decoded to: 0x50 - Write enable for volatile status register 0x06 - Write enable The former is used to modify volatile bits in the status register. For non-volatile bits the latter is needed. Preopcodes are used in SW sequencer to send one command "atomically" without anything else interfering the transfer. The sequence that gets executed is: - Send preopcode (write enable) from PREOP_OPTYPE register - Send the actual SPI command - Poll busy bit in the status register (0x05, RDSR) Commit 8c473dd61bb5 ("spi-nor: intel-spi: Don't assume OPMENU0/1 to be programmed by BIOS") enabled atomic sequence handling but because both preopcodes are programmed, the following happens: if (preop >> 8) val |= SSFSTS_CTL_SPOP; Since on these systems preop >> 8 == 0x50 we end up picking volatile write enable instead. Because of this the actual write command is pretty much NOP unless there is a WREN latched in the chip already. Furthermore we should not really just assume that WREN was issued in previous call to intel_spi_write_reg() because that might not be the case. This updates driver to first check that the opcode is actually available in PREOP_OPTYPE register and if not return error back to the spi-nor core (if the controller is not locked we program it now). In addition we save the opcode to ispi->atomic_preopcode field which is checked in next call to intel_spi_sw_cycle() to actually enable atomic sequence using the requested preopcode. Fixes: 8c473dd61bb5 ("spi-nor: intel-spi: Don't assume OPMENU0/1 to be programmed by BIOS") Signed-off-by: Mika Westerberg Cc: stable@vger.kernel.org Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/intel-spi.c | 78 ++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index 699951523179..8e98f4ab87c1 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -136,6 +136,7 @@ * @swseq_reg: Use SW sequencer in register reads/writes * @swseq_erase: Use SW sequencer in erase operation * @erase_64k: 64k erase supported + * @atomic_preopcode: Holds preopcode when atomic sequence is requested * @opcodes: Opcodes which are supported. This are programmed by BIOS * before it locks down the controller. */ @@ -153,6 +154,7 @@ struct intel_spi { bool swseq_reg; bool swseq_erase; bool erase_64k; + u8 atomic_preopcode; u8 opcodes[8]; }; @@ -474,7 +476,7 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len, int optype) { u32 val = 0, status; - u16 preop; + u8 atomic_preopcode; int ret; ret = intel_spi_opcode_index(ispi, opcode, optype); @@ -484,17 +486,42 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len, if (len > INTEL_SPI_FIFO_SZ) return -EINVAL; + /* + * Always clear it after each SW sequencer operation regardless + * of whether it is successful or not. + */ + atomic_preopcode = ispi->atomic_preopcode; + ispi->atomic_preopcode = 0; + /* Only mark 'Data Cycle' bit when there is data to be transferred */ if (len > 0) val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; val |= ret << SSFSTS_CTL_COP_SHIFT; val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; val |= SSFSTS_CTL_SCGO; - preop = readw(ispi->sregs + PREOP_OPTYPE); - if (preop) { - val |= SSFSTS_CTL_ACS; - if (preop >> 8) - val |= SSFSTS_CTL_SPOP; + if (atomic_preopcode) { + u16 preop; + + switch (optype) { + case OPTYPE_WRITE_NO_ADDR: + case OPTYPE_WRITE_WITH_ADDR: + /* Pick matching preopcode for the atomic sequence */ + preop = readw(ispi->sregs + PREOP_OPTYPE); + if ((preop & 0xff) == atomic_preopcode) + ; /* Do nothing */ + else if ((preop >> 8) == atomic_preopcode) + val |= SSFSTS_CTL_SPOP; + else + return -EINVAL; + + /* Enable atomic sequence */ + val |= SSFSTS_CTL_ACS; + break; + + default: + return -EINVAL; + } + } writel(val, ispi->sregs + SSFSTS_CTL); @@ -538,13 +565,31 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) /* * This is handled with atomic operation and preop code in Intel - * controller so skip it here now. If the controller is not locked, - * program the opcode to the PREOP register for later use. + * controller so we only verify that it is available. If the + * controller is not locked, program the opcode to the PREOP + * register for later use. + * + * When hardware sequencer is used there is no need to program + * any opcodes (it handles them automatically as part of a command). */ if (opcode == SPINOR_OP_WREN) { - if (!ispi->locked) - writel(opcode, ispi->sregs + PREOP_OPTYPE); + u16 preop; + if (!ispi->swseq_reg) + return 0; + + preop = readw(ispi->sregs + PREOP_OPTYPE); + if ((preop & 0xff) != opcode && (preop >> 8) != opcode) { + if (ispi->locked) + return -EINVAL; + writel(opcode, ispi->sregs + PREOP_OPTYPE); + } + + /* + * This enables atomic sequence on next SW sycle. Will + * be cleared after next operation. + */ + ispi->atomic_preopcode = opcode; return 0; } @@ -569,6 +614,13 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, u32 val, status; ssize_t ret; + /* + * Atomic sequence is not expected with HW sequencer reads. Make + * sure it is cleared regardless. + */ + if (WARN_ON_ONCE(ispi->atomic_preopcode)) + ispi->atomic_preopcode = 0; + switch (nor->read_opcode) { case SPINOR_OP_READ: case SPINOR_OP_READ_FAST: @@ -627,6 +679,9 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, u32 val, status; ssize_t ret; + /* Not needed with HW sequencer write, make sure it is cleared */ + ispi->atomic_preopcode = 0; + while (len > 0) { block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); @@ -707,6 +762,9 @@ static int intel_spi_erase(struct spi_nor *nor, loff_t offs) return 0; } + /* Not needed with HW sequencer erase, make sure it is cleared */ + ispi->atomic_preopcode = 0; + while (len > 0) { writel(offs, ispi->base + FADDR); From 1f37033f05bf924b7f2d84a818fbba8dc2eac528 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 5 Feb 2018 14:33:00 +0300 Subject: [PATCH 08/15] mtd: spi-nor: intel-spi: Explicitly mark the driver as dangerous in Kconfig The driver is not meant for normal users at all but instead such users who really know what they are doing and are able to build their own kernel to enable it. Mark both driver Kconfig entries as dangerous to make sure the driver is not accidentally enabled without understanding possible consequences in doing so. Signed-off-by: Mika Westerberg Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 89da88e59121..f480b227a6b8 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -90,7 +90,7 @@ config SPI_INTEL_SPI tristate config SPI_INTEL_SPI_PCI - tristate "Intel PCH/PCU SPI flash PCI driver" + tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)" depends on X86 && PCI select SPI_INTEL_SPI help @@ -106,7 +106,7 @@ config SPI_INTEL_SPI_PCI will be called intel-spi-pci. config SPI_INTEL_SPI_PLATFORM - tristate "Intel PCH/PCU SPI flash platform driver" + tristate "Intel PCH/PCU SPI flash platform driver (DANGEROUS)" depends on X86 select SPI_INTEL_SPI help From dd50a1c4e56d6d2ea753f87a35b1f1e09cb877d7 Mon Sep 17 00:00:00 2001 From: Yogesh Gaur Date: Tue, 2 Jan 2018 16:09:12 +0530 Subject: [PATCH 09/15] mtd: spi-nor: fsl-quadspi: fix api naming typo _init_ahb_read Fix api naming typo _init_ahb_read fsl_qspi_init_abh_read --> fsl_qspi_init_ahb_read Signed-off-by: Yogesh Gaur Acked-by: Han Xu Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/fsl-quadspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 3e3c0bbc45c0..1b7f9aa694ea 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -661,7 +661,7 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q) * causes the controller to clear the buffer, and use the sequence pointed * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. */ -static void fsl_qspi_init_abh_read(struct fsl_qspi *q) +static void fsl_qspi_init_ahb_read(struct fsl_qspi *q) { void __iomem *base = q->iobase; int seqid; @@ -795,7 +795,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) fsl_qspi_init_lut(q); /* Init for AHB read */ - fsl_qspi_init_abh_read(q); + fsl_qspi_init_ahb_read(q); return 0; } From aba3a882a178c47b2dab1fd0bccca6131c01d9bb Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 13 Feb 2017 09:13:42 +0100 Subject: [PATCH 10/15] mtd: spi-nor: intel: provide a range for poll_timout The overall poll time here is INTEL_SPI_TIMEOUT * 1000 which is 5000 * 1000 - so 5seconds and it is coded as a tight loop here delay_us to readl_poll_timeout() is set to 0. As this is never called in an atomic context sleeping should be no issue and there is no reasons for the tight-loop here. Signed-off-by: Nicholas Mc Guire Acked-by: Mika Westerberg Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/intel-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index 8e98f4ab87c1..d2cbfc27826e 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -287,7 +287,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), 0, + !(val & HSFSTS_CTL_SCIP), 40, INTEL_SPI_TIMEOUT * 1000); } @@ -296,7 +296,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), 0, + !(val & SSFSTS_CTL_SCIP), 40, INTEL_SPI_TIMEOUT * 1000); } From 3278aa0ec39194d3aa719919c0f366867f1266eb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:25:47 +0200 Subject: [PATCH 11/15] mtd: spi-nor: stm32-quadspi: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Cyrille Pitchen Cc: Marek Vasut Cc: David Woodhouse Cc: Brian Norris Cc: Boris Brezillon Cc: Richard Weinberger Cc: Maxime Coquelin Cc: Alexandre Torgue Cc: linux-mtd@lists.infradead.org Signed-off-by: Philipp Zabel Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/stm32-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index b3c7f6addba7..72553506a00b 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -656,7 +656,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) return ret; } - rstc = devm_reset_control_get(dev, NULL); + rstc = devm_reset_control_get_exclusive(dev, NULL); if (!IS_ERR(rstc)) { reset_control_assert(rstc); udelay(2); From d728a7ea9037c2df085bf9494d56e90d0ff69d7d Mon Sep 17 00:00:00 2001 From: Yogesh Gaur Date: Tue, 30 Jan 2018 22:49:58 +0530 Subject: [PATCH 12/15] mtd: spi-nor: fsl-quadspi: add support for ls2080a/ls1080a LS2080a/LS1088a supports Freescale Quad SPI controller. Add fsl-quadspi driver support for ls2080a and ls1088a chip. Signed-off-by: Suresh Gupta Signed-off-by: Yogesh Gaur Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/fsl-quadspi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 1b7f9aa694ea..7d9620c7ff6c 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -214,6 +214,7 @@ enum fsl_qspi_devtype { FSL_QUADSPI_IMX7D, FSL_QUADSPI_IMX6UL, FSL_QUADSPI_LS1021A, + FSL_QUADSPI_LS2080A, }; struct fsl_qspi_devtype_data { @@ -267,6 +268,15 @@ static struct fsl_qspi_devtype_data ls1021a_data = { .driver_data = 0, }; +static const struct fsl_qspi_devtype_data ls2080a_data = { + .devtype = FSL_QUADSPI_LS2080A, + .rxfifo = 128, + .txfifo = 64, + .ahb_buf_size = 1024, + .driver_data = QUADSPI_QUIRK_TKT253890, +}; + + #define FSL_QSPI_MAX_CHIP 4 struct fsl_qspi { struct spi_nor nor[FSL_QSPI_MAX_CHIP]; @@ -806,6 +816,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = { { .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, }, { .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, }, { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, }, + { .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); From 7fccf56ea4faef3f1e704acc18b8576b2eb9989d Mon Sep 17 00:00:00 2001 From: Stephen Douthit Date: Wed, 7 Mar 2018 18:55:57 -0500 Subject: [PATCH 13/15] mtd: spi-nor: Add Winbond w25q32jv support Datasheet: https://www.winbond.com/resource-files/w25q32jv%20dtr%20revf%2002242017.pdf Minimal testing done with fw_printenv/fw_setenv, test board did not support dual or quad access. Signed-off-by: Stephen Douthit Tested-by: Stephen Douthit Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 494b7a269872..3dda39b1cae9 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1215,6 +1215,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) }, + { + "w25q32jv", INFO(0xef7016, 0, 64 * 1024, 64, + 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) }, { From d616f81cdd2a21edfa90a595a4e9b143f5ba8414 Mon Sep 17 00:00:00 2001 From: Kimmo Rautkoski Date: Mon, 14 May 2018 13:15:53 +0300 Subject: [PATCH 14/15] mtd: spi-nor: Add support for is25wp series chips Added support for is25wp032, is25wp064 and is25wp128. Signed-off-by: Kimmo Rautkoski Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3dda39b1cae9..e6ead30d5949 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1065,6 +1065,12 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ) }, + { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, /* Macronix */ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, From 771ff17e82fac54686f149e311d4ea74a70255b1 Mon Sep 17 00:00:00 2001 From: YuheiOKAWA Date: Thu, 17 May 2018 11:40:27 +0900 Subject: [PATCH 15/15] mtd: spi-nor: Add support for EN25QH32 Add support for Eon en25qh32 spi nor flash. Signed-off-by: YuheiOKAWA Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index e6ead30d5949..d9c368c44194 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -994,6 +994,7 @@ static const struct flash_info spi_nor_ids[] = { { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) }, { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) },