summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-02-22 09:19:08 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2021-02-22 09:19:08 -0800
commita2590d69893f232cbb79d149dbbb456a1febca22 (patch)
tree870326105cf0ff810fe9778764b276324fc6b1b9 /drivers/spi
parentd6560052c2f73db59834e9a3c0aba20579aa7059 (diff)
parenteec262d179ff60e8d12298ab2f118661040e0bf5 (diff)
downloadlinux-a2590d69893f232cbb79d149dbbb456a1febca22.tar.gz
linux-a2590d69893f232cbb79d149dbbb456a1febca22.tar.bz2
linux-a2590d69893f232cbb79d149dbbb456a1febca22.zip
Merge tag 'spi-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown: "The main focus of this release from a framework point of view has been spi-mem where we've acquired support for a few new hardware features which enable better performance on suitable hardware. Otherwise mostly thanks to Arnd's cleanup efforts on old platforms we've removed several obsolete drivers which just about balance out the newer drivers we've added this cycle. Summary: - Allow drivers to flag if they are unidirectional. - Support for DTR mode and hardware acceleration of dummy cycles in spi-mem. - Support for Allwinder H616, Intel Lightning Mountain, nVidia Tegra QuadSPI, Realtek RTL838x and RTL839x. - Removal of obsolete EFM32, Txx9 and SIRF Prima and Atlas drivers" * tag 'spi-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (76 commits) spi: Skip zero-length transfers in spi_transfer_one_message() spi: dw: Avoid stack content exposure spi: cadence-quadspi: Use spi_mem_dtr_supports_op() spi: spi-mem: add spi_mem_dtr_supports_op() spi: atmel-quadspi: Disable the QSPI IP at suspend() spi: pxa2xx: Add IDs for the controllers found on Intel Lynxpoint spi: pxa2xx: Fix the controller numbering for Wildcat Point spi: Change provied to provided in the file spi.h spi: mediatek: add set_cs_timing support spi: support CS timing for HW & SW mode spi: add power control when set_cs_timing spi: stm32: make spurious and overrun interrupts visible spi: stm32h7: replace private SPI_1HZ_NS with NSEC_PER_SEC spi: stm32: defer probe for reset spi: stm32: driver uses reset controller only at init spi: stm32h7: ensure message are smaller than max size spi: stm32: use bitfield macros spi: stm32: do not mandate cs_gpio spi: stm32: properly handle 0 byte transfer spi: clps711xx: remove redundant white-space ...
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig33
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/atmel-quadspi.c1
-rw-r--r--drivers/spi/spi-atmel.c2
-rw-r--r--drivers/spi/spi-au1550.c53
-rw-r--r--drivers/spi/spi-bcm-qspi.c2
-rw-r--r--drivers/spi/spi-bcm2835.c8
-rw-r--r--drivers/spi/spi-bcm2835aux.c2
-rw-r--r--drivers/spi/spi-cadence-quadspi.c333
-rw-r--r--drivers/spi/spi-clps711x.c2
-rw-r--r--drivers/spi/spi-dw-bt1.c2
-rw-r--r--drivers/spi/spi-efm32.c462
-rw-r--r--drivers/spi/spi-fsl-spi.c2
-rw-r--r--drivers/spi/spi-hisi-sfc-v3xx.c33
-rw-r--r--drivers/spi/spi-imx.c2
-rw-r--r--drivers/spi/spi-mem.c23
-rw-r--r--drivers/spi/spi-mpc52xx.c4
-rw-r--r--drivers/spi/spi-mt65xx.c72
-rw-r--r--drivers/spi/spi-orion.c55
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c29
-rw-r--r--drivers/spi/spi-pxa2xx.c4
-rw-r--r--drivers/spi/spi-qcom-qspi.c3
-rw-r--r--drivers/spi/spi-realtek-rtl.c209
-rw-r--r--drivers/spi/spi-rockchip.c2
-rw-r--r--drivers/spi/spi-rpc-if.c13
-rw-r--r--drivers/spi/spi-sh-msiof.c14
-rw-r--r--drivers/spi/spi-sirf.c1236
-rw-r--r--drivers/spi/spi-stm32.c150
-rw-r--r--drivers/spi/spi-synquacer.c4
-rw-r--r--drivers/spi/spi-tegra210-quad.c1410
-rw-r--r--drivers/spi/spi-txx9.c477
-rw-r--r--drivers/spi/spi.c59
32 files changed, 2272 insertions, 2434 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 74ea73a05981..09a263cf4ae2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -203,7 +203,7 @@ config SPI_CADENCE
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
- depends on OF && (ARM || ARM64 || COMPILE_TEST)
+ depends on OF && (ARM || ARM64 || X86 || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
@@ -292,13 +292,6 @@ config SPI_DLN2
This driver can also be built as a module. If so, the module
will be called spi-dln2.
-config SPI_EFM32
- tristate "EFM32 SPI controller"
- depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
- select SPI_BITBANG
- help
- Driver for the spi controller found on Energy Micro's EFM32 SoCs.
-
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
depends on ARCH_EP93XX || COMPILE_TEST
@@ -649,7 +642,7 @@ config SPI_RPCIF
tristate "Renesas RPC-IF SPI driver"
depends on RENESAS_RPCIF
help
- SPI driver for Renesas R-Car Gen3 RPC-IF.
+ SPI driver for Renesas R-Car Gen3 or RZ/G2 RPC-IF.
config SPI_RSPI
tristate "Renesas RSPI/QSPI controller"
@@ -750,13 +743,6 @@ config SPI_SIFIVE
help
This exposes the SPI controller IP from SiFive.
-config SPI_SIRF
- tristate "CSR SiRFprimaII SPI controller"
- depends on SIRF_DMA
- select SPI_BITBANG
- help
- SPI driver for CSR SiRFprimaII SoCs
-
config SPI_SLAVE_MT27XX
tristate "MediaTek SPI slave device"
depends on ARCH_MEDIATEK || COMPILE_TEST
@@ -842,6 +828,15 @@ config SPI_MXS
help
SPI driver for Freescale MXS devices.
+config SPI_TEGRA210_QUAD
+ tristate "NVIDIA Tegra QSPI Controller"
+ depends on ARCH_TEGRA || COMPILE_TEST
+ depends on RESET_CONTROLLER
+ help
+ QSPI driver for NVIDIA Tegra QSPI Controller interface. This
+ controller is different from the SPI controller and is available
+ on Tegra SoCs starting from Tegra210.
+
config SPI_TEGRA114
tristate "NVIDIA Tegra114 SPI Controller"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
@@ -884,12 +879,6 @@ config SPI_TOPCLIFF_PCH
This driver also supports the ML7213/ML7223/ML7831, a companion chip
for the Atom E6xx series and compatible with the Intel EG20T PCH.
-config SPI_TXX9
- tristate "Toshiba TXx9 SPI controller"
- depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST)
- help
- SPI driver for Toshiba TXx9 MIPS SoCs
-
config SPI_UNIPHIER
tristate "Socionext UniPhier SPI Controller"
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 6fea5821662e..0f06fc0813c6 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -42,7 +42,6 @@ spi-dw-$(CONFIG_SPI_DW_DMA) += spi-dw-dma.o
obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o
-obj-$(CONFIG_SPI_EFM32) += spi-efm32.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
obj-$(CONFIG_SPI_FSI) += spi-fsi.o
@@ -94,6 +93,7 @@ obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
+obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
@@ -105,7 +105,6 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
-obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o
obj-$(CONFIG_SPI_SPRD) += spi-sprd.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
@@ -115,6 +114,7 @@ obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_SYNQUACER) += spi-synquacer.o
+obj-$(CONFIG_SPI_TEGRA210_QUAD) += spi-tegra210-quad.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
@@ -122,7 +122,6 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o
obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
-obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_UNIPHIER) += spi-uniphier.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 10bc5390ab91..95d4fa32c299 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -657,6 +657,7 @@ static int __maybe_unused atmel_qspi_suspend(struct device *dev)
struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
clk_disable_unprepare(aq->qspick);
clk_disable_unprepare(aq->pclk);
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 948396b382d7..f429436082af 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1590,7 +1590,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
if (ret == 0) {
as->use_dma = true;
} else if (ret == -EPROBE_DEFER) {
- return ret;
+ goto out_unmap_regs;
}
} else if (as->caps.has_pdc_support) {
as->use_pdc = true;
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index dfb7196f4caf..4b59a1b1bf7e 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -26,7 +26,7 @@
#include <asm/mach-au1x00/au1550_spi.h>
-static unsigned usedma = 1;
+static unsigned int usedma = 1;
module_param(usedma, uint, 0644);
/*
@@ -43,9 +43,9 @@ struct au1550_spi {
volatile psc_spi_t __iomem *regs;
int irq;
- unsigned len;
- unsigned tx_count;
- unsigned rx_count;
+ unsigned int len;
+ unsigned int tx_count;
+ unsigned int rx_count;
const u8 *tx;
u8 *rx;
@@ -56,14 +56,14 @@ struct au1550_spi {
struct completion master_done;
- unsigned usedma;
+ unsigned int usedma;
u32 dma_tx_id;
u32 dma_rx_id;
u32 dma_tx_ch;
u32 dma_rx_ch;
u8 *dma_rx_tmpbuf;
- unsigned dma_rx_tmpbuf_size;
+ unsigned int dma_rx_tmpbuf_size;
u32 dma_rx_tmpbuf_addr;
struct spi_master *master;
@@ -74,8 +74,7 @@ struct au1550_spi {
/* we use an 8-bit memory device for dma transfers to/from spi fifo */
-static dbdev_tab_t au1550_spi_mem_dbdev =
-{
+static dbdev_tab_t au1550_spi_mem_dbdev = {
.dev_id = DBDMA_MEM_CHAN,
.dev_flags = DEV_FLAGS_ANYUSE|DEV_FLAGS_SYNC,
.dev_tsize = 0,
@@ -99,7 +98,7 @@ static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw);
* BRG valid range is 4..63
* DIV valid range is 0..3
*/
-static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned speed_hz)
+static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned int speed_hz)
{
u32 mainclk_hz = hw->pdata->mainclk_hz;
u32 div, brg;
@@ -161,7 +160,7 @@ static void au1550_spi_reset_fifos(struct au1550_spi *hw)
static void au1550_spi_chipsel(struct spi_device *spi, int value)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
- unsigned cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+ unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
u32 cfg, stat;
switch (value) {
@@ -221,7 +220,7 @@ static void au1550_spi_chipsel(struct spi_device *spi, int value)
static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
- unsigned bpw, hz;
+ unsigned int bpw, hz;
u32 cfg, stat;
if (t) {
@@ -276,7 +275,7 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
* spi master done event irq is not generated unless rx fifo is empty (emptied)
* so we need rx tmp buffer to use for rx dma if user does not provide one
*/
-static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size)
+static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned int size)
{
hw->dma_rx_tmpbuf = kmalloc(size, GFP_KERNEL);
if (!hw->dma_rx_tmpbuf)
@@ -399,10 +398,10 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
DMA_FROM_DEVICE);
}
/* unmap buffers if mapped above */
- if (t->rx_buf && t->rx_dma == 0 )
+ if (t->rx_buf && t->rx_dma == 0)
dma_unmap_single(hw->dev, dma_rx_addr, t->len,
DMA_FROM_DEVICE);
- if (t->tx_buf && t->tx_dma == 0 )
+ if (t->tx_buf && t->tx_dma == 0)
dma_unmap_single(hw->dev, dma_tx_addr, t->len,
DMA_TO_DEVICE);
@@ -447,8 +446,8 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
"dma transfer: receive FIFO overflow!\n");
else
dev_err(hw->dev,
- "dma transfer: unexpected SPI error "
- "(event=0x%x stat=0x%x)!\n", evnt, stat);
+ "dma transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
+ evnt, stat);
complete(&hw->master_done);
return IRQ_HANDLED;
@@ -493,12 +492,12 @@ static void au1550_spi_tx_word_##size(struct au1550_spi *hw) \
wmb(); /* drain writebuffer */ \
}
-AU1550_SPI_RX_WORD(8,0xff)
-AU1550_SPI_RX_WORD(16,0xffff)
-AU1550_SPI_RX_WORD(32,0xffffff)
-AU1550_SPI_TX_WORD(8,0xff)
-AU1550_SPI_TX_WORD(16,0xffff)
-AU1550_SPI_TX_WORD(32,0xffffff)
+AU1550_SPI_RX_WORD(8, 0xff)
+AU1550_SPI_RX_WORD(16, 0xffff)
+AU1550_SPI_RX_WORD(32, 0xffffff)
+AU1550_SPI_TX_WORD(8, 0xff)
+AU1550_SPI_TX_WORD(16, 0xffff)
+AU1550_SPI_TX_WORD(32, 0xffffff)
static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
{
@@ -567,8 +566,8 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
au1550_spi_mask_ack_all(hw);
au1550_spi_reset_fifos(hw);
dev_err(hw->dev,
- "pio transfer: unexpected SPI error "
- "(event=0x%x stat=0x%x)!\n", evnt, stat);
+ "pio transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
+ evnt, stat);
complete(&hw->master_done);
return IRQ_HANDLED;
}
@@ -636,12 +635,14 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+
return hw->txrx_bufs(spi, t);
}
static irqreturn_t au1550_spi_irq(int irq, void *dev)
{
struct au1550_spi *hw = dev;
+
return hw->irq_callback(hw);
}
@@ -872,6 +873,7 @@ static int au1550_spi_probe(struct platform_device *pdev)
{
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
+
master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
master->min_speed_hz =
hw->pdata->mainclk_hz / (max_div + 1) + 1;
@@ -972,8 +974,7 @@ static int __init au1550_spi_init(void)
if (usedma) {
ddma_memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
if (!ddma_memid)
- printk(KERN_ERR "au1550-spi: cannot add memory"
- "dbdma device\n");
+ printk(KERN_ERR "au1550-spi: cannot add memory dbdma device\n");
}
return platform_driver_register(&au1550_spi_drv);
}
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index c028446c7460..707fe3a5d8ef 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -881,7 +881,7 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
* when using flex mode we need to send
* the upper address byte to bspi
*/
- if (bcm_qspi_bspi_ver_three(qspi) == false) {
+ if (!bcm_qspi_bspi_ver_three(qspi)) {
addr = from & 0xff000000;
bcm_qspi_write(qspi, BSPI,
BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 197485f2c2b2..8965fe61c8b4 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -386,7 +386,7 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw(bs);
/* wake up the framework */
- complete(&bs->ctlr->xfer_completion);
+ spi_finalize_current_transfer(bs->ctlr);
}
return IRQ_HANDLED;
@@ -608,7 +608,7 @@ static void bcm2835_spi_dma_rx_done(void *data)
bcm2835_spi_reset_hw(bs);
/* and mark as completed */;
- complete(&ctlr->xfer_completion);
+ spi_finalize_current_transfer(ctlr);
}
/**
@@ -640,7 +640,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
bcm2835_spi_undo_prologue(bs);
bcm2835_spi_reset_hw(bs);
- complete(&ctlr->xfer_completion);
+ spi_finalize_current_transfer(ctlr);
}
/**
@@ -1307,6 +1307,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(bs->clk),
"could not get clk\n");
+ ctlr->max_speed_hz = clk_get_rate(bs->clk) / 2;
+
bs->irq = platform_get_irq(pdev, 0);
if (bs->irq <= 0)
return bs->irq ? bs->irq : -ENODEV;
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 1a26865c42f8..75589ac6e95f 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -254,7 +254,7 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
/* and if rx_len is 0 then disable interrupts and wake up completion */
if (!bs->rx_len) {
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
- complete(&master->xfer_completion);
+ spi_finalize_current_transfer(master);
}
return IRQ_HANDLED;
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index ba7d40c2922f..442cc7c53a47 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -52,6 +52,7 @@ struct cqspi_flash_pdata {
u8 inst_width;
u8 addr_width;
u8 data_width;
+ bool dtr;
u8 cs;
};
@@ -75,6 +76,7 @@ struct cqspi_st {
bool is_decoded_cs;
u32 fifo_depth;
u32 fifo_width;
+ u32 num_chipselect;
bool rclk_en;
u32 trigger_address;
u32 wr_delay;
@@ -111,6 +113,8 @@ struct cqspi_driver_platdata {
#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_DTR_PROTO BIT(24)
+#define CQSPI_REG_CONFIG_DUAL_OPCODE BIT(30)
#define CQSPI_REG_CONFIG_IDLE_LSB 31
#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
@@ -173,6 +177,9 @@ struct cqspi_driver_platdata {
#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
+#define CQSPI_REG_WR_COMPLETION_CTRL 0x38
+#define CQSPI_REG_WR_DISABLE_AUTO_POLL BIT(14)
+
#define CQSPI_REG_IRQSTATUS 0x40
#define CQSPI_REG_IRQMASK 0x44
@@ -188,6 +195,7 @@ struct cqspi_driver_platdata {
#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_DUMMY_LSB 7
#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
@@ -198,6 +206,7 @@ struct cqspi_driver_platdata {
#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_CMDCTRL_DUMMY_MASK 0x1F
#define CQSPI_REG_INDIRECTWR 0x70
#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0)
@@ -214,6 +223,14 @@ struct cqspi_driver_platdata {
#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
+#define CQSPI_REG_POLLING_STATUS 0xB0
+#define CQSPI_REG_POLLING_STATUS_DUMMY_LSB 16
+
+#define CQSPI_REG_OP_EXT_LOWER 0xE0
+#define CQSPI_REG_OP_EXT_READ_LSB 24
+#define CQSPI_REG_OP_EXT_WRITE_LSB 16
+#define CQSPI_REG_OP_EXT_STIG_LSB 0
+
/* Interrupt status bits */
#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
@@ -288,6 +305,80 @@ static unsigned int cqspi_calc_rdreg(struct cqspi_flash_pdata *f_pdata)
return rdreg;
}
+static unsigned int cqspi_calc_dummy(const struct spi_mem_op *op, bool dtr)
+{
+ unsigned int dummy_clk;
+
+ dummy_clk = op->dummy.nbytes * (8 / op->dummy.buswidth);
+ if (dtr)
+ dummy_clk /= 2;
+
+ return dummy_clk;
+}
+
+static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata,
+ const struct spi_mem_op *op)
+{
+ f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
+ f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
+ f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
+ f_pdata->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr;
+
+ switch (op->data.buswidth) {
+ case 0:
+ break;
+ case 1:
+ f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
+ break;
+ case 2:
+ f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
+ break;
+ case 4:
+ f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
+ break;
+ case 8:
+ f_pdata->data_width = CQSPI_INST_TYPE_OCTAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Right now we only support 8-8-8 DTR mode. */
+ if (f_pdata->dtr) {
+ switch (op->cmd.buswidth) {
+ case 0:
+ break;
+ case 8:
+ f_pdata->inst_width = CQSPI_INST_TYPE_OCTAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (op->addr.buswidth) {
+ case 0:
+ break;
+ case 8:
+ f_pdata->addr_width = CQSPI_INST_TYPE_OCTAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (op->data.buswidth) {
+ case 0:
+ break;
+ case 8:
+ f_pdata->data_width = CQSPI_INST_TYPE_OCTAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int cqspi_wait_idle(struct cqspi_st *cqspi)
{
const unsigned int poll_idle_retry = 3;
@@ -345,19 +436,85 @@ static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
return cqspi_wait_idle(cqspi);
}
+static int cqspi_setup_opcode_ext(struct cqspi_flash_pdata *f_pdata,
+ const struct spi_mem_op *op,
+ unsigned int shift)
+{
+ struct cqspi_st *cqspi = f_pdata->cqspi;
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+ u8 ext;
+
+ if (op->cmd.nbytes != 2)
+ return -EINVAL;
+
+ /* Opcode extension is the LSB. */
+ ext = op->cmd.opcode & 0xff;
+
+ reg = readl(reg_base + CQSPI_REG_OP_EXT_LOWER);
+ reg &= ~(0xff << shift);
+ reg |= ext << shift;
+ writel(reg, reg_base + CQSPI_REG_OP_EXT_LOWER);
+
+ return 0;
+}
+
+static int cqspi_enable_dtr(struct cqspi_flash_pdata *f_pdata,
+ const struct spi_mem_op *op, unsigned int shift,
+ bool enable)
+{
+ struct cqspi_st *cqspi = f_pdata->cqspi;
+ void __iomem *reg_base = cqspi->iobase;
+ unsigned int reg;
+ int ret;
+
+ reg = readl(reg_base + CQSPI_REG_CONFIG);
+
+ /*
+ * We enable dual byte opcode here. The callers have to set up the
+ * extension opcode based on which type of operation it is.
+ */
+ if (enable) {
+ reg |= CQSPI_REG_CONFIG_DTR_PROTO;
+ reg |= CQSPI_REG_CONFIG_DUAL_OPCODE;
+
+ /* Set up command opcode extension. */
+ ret = cqspi_setup_opcode_ext(f_pdata, op, shift);
+ if (ret)
+ return ret;
+ } else {
+ reg &= ~CQSPI_REG_CONFIG_DTR_PROTO;
+ reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE;
+ }
+
+ writel(reg, reg_base + CQSPI_REG_CONFIG);
+
+ return cqspi_wait_idle(cqspi);
+}
+
static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
const struct spi_mem_op *op)
{
struct cqspi_st *cqspi = f_pdata->cqspi;
void __iomem *reg_base = cqspi->iobase;
u8 *rxbuf = op->data.buf.in;
- u8 opcode = op->cmd.opcode;
+ u8 opcode;
size_t n_rx = op->data.nbytes;
unsigned int rdreg;
unsigned int reg;
+ unsigned int dummy_clk;
size_t read_len;
int status;
+ status = cqspi_set_protocol(f_pdata, op);
+ if (status)
+ return status;
+
+ status = cqspi_enable_dtr(f_pdata, op, CQSPI_REG_OP_EXT_STIG_LSB,
+ f_pdata->dtr);
+ if (status)
+ return status;
+
if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
dev_err(&cqspi->pdev->dev,
"Invalid input argument, len %zu rxbuf 0x%p\n",
@@ -365,11 +522,24 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
return -EINVAL;
}
+ if (f_pdata->dtr)
+ opcode = op->cmd.opcode >> 8;
+ else
+ opcode = op->cmd.opcode;
+
reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
rdreg = cqspi_calc_rdreg(f_pdata);
writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
+ dummy_clk = cqspi_calc_dummy(op, f_pdata->dtr);
+ if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
+ return -EOPNOTSUPP;
+
+ if (dummy_clk)
+ reg |= (dummy_clk & CQSPI_REG_CMDCTRL_DUMMY_MASK)
+ << CQSPI_REG_CMDCTRL_DUMMY_LSB;
+
reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
/* 0 means 1 byte. */
@@ -401,12 +571,22 @@ static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
{
struct cqspi_st *cqspi = f_pdata->cqspi;
void __iomem *reg_base = cqspi->iobase;
- const u8 opcode = op->cmd.opcode;
+ u8 opcode;
const u8 *txbuf = op->data.buf.out;
size_t n_tx = op->data.nbytes;
unsigned int reg;
unsigned int data;
size_t write_len;
+ int ret;
+
+ ret = cqspi_set_protocol(f_pdata, op);
+ if (ret)
+ return ret;
+
+ ret = cqspi_enable_dtr(f_pdata, op, CQSPI_REG_OP_EXT_STIG_LSB,
+ f_pdata->dtr);
+ if (ret)
+ return ret;
if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) {
dev_err(&cqspi->pdev->dev,
@@ -415,6 +595,14 @@ static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
return -EINVAL;
}
+ reg = cqspi_calc_rdreg(f_pdata);
+ writel(reg, reg_base + CQSPI_REG_RD_INSTR);
+
+ if (f_pdata->dtr)
+ opcode = op->cmd.opcode >> 8;
+ else
+ opcode = op->cmd.opcode;
+
reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
if (op->addr.nbytes) {
@@ -454,14 +642,27 @@ static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata,
void __iomem *reg_base = cqspi->iobase;
unsigned int dummy_clk = 0;
unsigned int reg;
+ int ret;
+ u8 opcode;
+
+ ret = cqspi_enable_dtr(f_pdata, op, CQSPI_REG_OP_EXT_READ_LSB,
+ f_pdata->dtr);
+ if (ret)
+ return ret;
- reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+ if (f_pdata->dtr)
+ opcode = op->cmd.opcode >> 8;
+ else
+ opcode = op->cmd.opcode;
+
+ reg = opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
reg |= cqspi_calc_rdreg(f_pdata);
/* Setup dummy clock cycles */
- dummy_clk = op->dummy.nbytes * 8;
+ dummy_clk = cqspi_calc_dummy(op, f_pdata->dtr);
+
if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
- dummy_clk = CQSPI_DUMMY_CLKS_MAX;
+ return -EOPNOTSUPP;
if (dummy_clk)
reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
@@ -573,15 +774,43 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
const struct spi_mem_op *op)
{
unsigned int reg;
+ int ret;
struct cqspi_st *cqspi = f_pdata->cqspi;
void __iomem *reg_base = cqspi->iobase;
+ u8 opcode;
+
+ ret = cqspi_enable_dtr(f_pdata, op, CQSPI_REG_OP_EXT_WRITE_LSB,
+ f_pdata->dtr);
+ if (ret)
+ return ret;
+
+ if (f_pdata->dtr)
+ opcode = op->cmd.opcode >> 8;
+ else
+ opcode = op->cmd.opcode;
/* Set opcode. */
- reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+ reg = opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+ reg |= f_pdata->data_width << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
+ reg |= f_pdata->addr_width << CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB;
writel(reg, reg_base + CQSPI_REG_WR_INSTR);
reg = cqspi_calc_rdreg(f_pdata);
writel(reg, reg_base + CQSPI_REG_RD_INSTR);
+ if (f_pdata->dtr) {
+ /*
+ * Some flashes like the cypress Semper flash expect a 4-byte
+ * dummy address with the Read SR command in DTR mode, but this
+ * controller does not support sending address with the Read SR
+ * command. So, disable write completion polling on the
+ * controller's side. spi-nor will take care of polling the
+ * status register.
+ */
+ reg = readl(reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
+ reg |= CQSP