diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-03 20:08:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-08-03 20:08:51 -0700 |
commit | b171373902b06d1b5a775de74178bf1527fee6cc (patch) | |
tree | 57f28f0d401457437dcd4945f15e10d13832b24f /drivers/mtd | |
parent | bbb839901fe865a56d91aa88d70908a7d16268a1 (diff) | |
parent | 11ba28229f8258164731e42f4c3e93762cb6578e (diff) |
Merge tag 'spi-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"A fairly quiet release for SPI, nothing really going on in the core
although there's been quite a bit of driver related activity.
This includes the addition of some shared code in drivers/memory for
the Renesas RPC-IF which is used by a newly added SPI driver, the
memory subsystem doesn't seem to have a fixed maintainer at the minute
and this seemed like the most sensible way to get that hardware
supported.
- Quite a few cleanups and optimizations for the Altera, Qualcomm
GENI, sun6i and lantiq drivers.
- Several more GPIO descriptor conversions.
- Move the Cadence QuadSPI driver from drivers/mtd to drivers/spi.
- New support for Mediatek MT8192 and Renesas RPC-IF, R8A7742 and
R8A774e1"
* tag 'spi-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (119 commits)
dt-bindings: lpspi: New property in document DT bindings for LPSPI
spi: lpspi: fix using CS discontinuously on i.MX8DXLEVK
spi: lpspi: remove unused fsl_lpspi->chipselect
spi: lpspi: Fix kernel warning dump when probe fail after calling spi_register
spi: rockchip: Fix error in SPI slave pio read
spi: rockchip: Support 64-location deep FIFOs
spi: rockchip: Config spi rx dma burst size depend on xfer length
spi: spi-topcliff-pch: drop call to wakeup-disable
spi: spidev: Align buffers for DMA
spi: correct kernel-doc inconsistency
spi: sun4i: update max transfer size reported
spi: imx: enable runtime pm support
spi: update bindings for MT8192 SoC
spi: mediatek: add spi support for mt8192 IC
spi: Add bindings for Lightning Mountain SoC
spi: lantiq: Add support to Lightning Mountain SoC
spi: lantiq: Move interrupt configuration to SoC specific data structure
spi: lantiq: Add fifo size bit mask in SoC specific data structure
spi: lantiq: Add support to acknowledge interrupt
spi: lantiq: Move interrupt control register offesets to SoC specific data structure
...
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 |
3 files changed, 0 insertions, 1552 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>"); |