aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig15
-rw-r--r--drivers/spi/spi-mem.c2
-rw-r--r--drivers/spi/spi-xilinx.c1055
-rw-r--r--drivers/spi/spi-zynq-qspi.c43
-rw-r--r--drivers/spi/spi-zynqmp-gqspi.c402
-rw-r--r--drivers/spi/spi.c8
6 files changed, 1132 insertions, 393 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 30a40280c157..f6971237b7cc 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -851,11 +851,18 @@ config SPI_XTENSA_XTFPGA
config SPI_ZYNQ_QSPI
tristate "Xilinx Zynq QSPI controller"
- depends on ARCH_ZYNQ || COMPILE_TEST
+ depends on ARCH_ZYNQ
+ depends on SPI_MASTER
help
- This enables support for the Zynq Quad SPI controller
- in master mode.
- This controller only supports SPI memory interface.
+ This selects the Xilinx ZYNQ Quad SPI controller master driver.
+
+config SPI_ZYNQ_QSPI_DUAL_STACKED
+ bool "Xilinx Zynq QSPI Dual stacked configuration"
+ depends on SPI_ZYNQ_QSPI
+ help
+ This selects the Xilinx ZYNQ Quad SPI controller in dual stacked mode.
+ Enable this option if your hw design is using dual stacked
+ configuration.
config SPI_ZYNQMP_GQSPI
tristate "Xilinx ZynqMP GQSPI controller"
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index de0ba3e5449f..550f3ff36fa3 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -348,6 +348,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1;
xfers[xferpos].len = op->dummy.nbytes;
xfers[xferpos].tx_nbits = op->dummy.buswidth;
+ xfers[xferpos].dummy = op->dummy.nbytes * 8;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->dummy.nbytes;
@@ -362,6 +363,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_nbits = op->data.buswidth;
}
+ xfers[xferpos].stripe = update_stripe(op->cmd.opcode);
xfers[xferpos].len = op->data.nbytes;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index d5f9d5fbb3e8..b3d2cc5cb6ec 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -16,10 +16,11 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
#include <linux/spi/xilinx_spi.h>
#include <linux/io.h>
-
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
#define XILINX_SPI_MAX_CS 32
#define XILINX_SPI_NAME "xilinx_spi"
@@ -27,8 +28,18 @@
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
* Product Specification", DS464
*/
-#define XSPI_CR_OFFSET 0x60 /* Control Register */
-
+/* Register Offsets */
+#define XSPI_CR_OFFSET 0x60
+#define XSPI_SR_OFFSET 0x64
+#define XSPI_TXD_OFFSET 0x68
+#define XSPI_RXD_OFFSET 0x6c
+#define XSPI_SSR_OFFSET 0x70
+#define XIPIF_V123B_DGIER_OFFSET 0x1c
+#define XIPIF_V123B_IISR_OFFSET 0x20
+#define XIPIF_V123B_IIER_OFFSET 0x28
+#define XIPIF_V123B_RESETR_OFFSET 0x40
+
+/* Register bit masks */
#define XSPI_CR_LOOP 0x01
#define XSPI_CR_ENABLE 0x02
#define XSPI_CR_MASTER_MODE 0x04
@@ -41,133 +52,203 @@
#define XSPI_CR_MANUAL_SSELECT 0x80
#define XSPI_CR_TRANS_INHIBIT 0x100
#define XSPI_CR_LSB_FIRST 0x200
-
-#define XSPI_SR_OFFSET 0x64 /* Status Register */
-
-#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
-#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
-#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */
-#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
-#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
-
-#define XSPI_TXD_OFFSET 0x68 /* Data Transmit Register */
-#define XSPI_RXD_OFFSET 0x6c /* Data Receive Register */
-
-#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
-
-/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
- * IPIF registers are 32 bit
- */
-#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */
+#define XSPI_SR_RX_EMPTY_MASK 0x01
+#define XSPI_SR_RX_FULL_MASK 0x02
+#define XSPI_SR_TX_EMPTY_MASK 0x04
+#define XSPI_SR_TX_FULL_MASK 0x08
+#define XSPI_SR_MODE_FAULT_MASK 0x10
#define XIPIF_V123B_GINTR_ENABLE 0x80000000
-
-#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */
-#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */
-
-#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */
-#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while
- * disabled */
-#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */
-#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
-#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
-#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */
-#define XSPI_INTR_TX_HALF_EMPTY 0x40 /* TxFIFO is half empty */
-
-#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
-#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
-
+#define XSPI_INTR_MODE_FAULT 0x01
+#define XSPI_INTR_SLAVE_MODE_FAULT 0x02
+#define XSPI_INTR_TX_EMPTY 0x04
+#define XSPI_INTR_TX_UNDERRUN 0x08
+#define XSPI_INTR_RX_FULL 0x10
+#define XSPI_INTR_RX_OVERRUN 0x20
+#define XSPI_INTR_TX_HALF_EMPTY 0x40
+#define XIPIF_V123B_RESET_MASK 0x0a
+
+/* Number of bits per word */
+#define XSPI_ONE_BITS_PER_WORD 1
+#define XSPI_TWO_BITS_PER_WORD 2
+#define XSPI_FOUR_BITS_PER_WORD 4
+
+/* Number of data lines used to receive */
+#define XSPI_RX_ONE_WIRE 1
+#define XSPI_RX_FOUR_WIRE 4
+
+/* Auto suspend timeout in milliseconds */
+#define SPI_AUTOSUSPEND_TIMEOUT 3000
+
+/* Command used for Dummy read Id */
+#define SPI_READ_ID 0x9F
+
+/**
+ * struct xilinx_spi - This definition define spi driver instance
+ * @regs: virt. address of the control registers
+ * @irq: IRQ number
+ * @axi_clk: Pointer to the AXI clock
+ * @axi4_clk: Pointer to the AXI4 clock
+ * @spi_clk: Pointer to the SPI clock
+ * @dev: Pointer to the device
+ * @rx_ptr: Pointer to the RX buffer
+ * @tx_ptr: Pointer to the TX buffer
+ * @bytes_per_word: Number of bytes in a word
+ * @buffer_size: Buffer size in words
+ * @cs_inactive: Level of the CS pins when inactive
+ * @read_fn: For reading data from SPI registers
+ * @write_fn: For writing data to SPI registers
+ * @bytes_to_transfer: Number of bytes left to transfer
+ * @bytes_to_receive: Number of bytes left to receive
+ * @rx_bus_width: Number of wires used to receive data
+ * @tx_fifo: For writing data to fifo
+ * @rx_fifo: For reading data from fifo
+ */
struct xilinx_spi {
- /* bitbang has to be first */
- struct spi_bitbang bitbang;
- struct completion done;
- void __iomem *regs; /* virt. address of the control registers */
-
- int irq;
-
- u8 *rx_ptr; /* pointer in the Tx buffer */
- const u8 *tx_ptr; /* pointer in the Rx buffer */
+ void __iomem *regs;
+ int irq;
+ struct clk *axi_clk;
+ struct clk *axi4_clk;
+ struct clk *spi_clk;
+ struct device *dev;
+ u8 *rx_ptr;
+ const u8 *tx_ptr;
u8 bytes_per_word;
- int buffer_size; /* buffer size in words */
- u32 cs_inactive; /* Level of the CS pins when inactive*/
- unsigned int (*read_fn)(void __iomem *);
- void (*write_fn)(u32, void __iomem *);
+ int buffer_size;
+ u32 cs_inactive;
+ unsigned int (*read_fn)(void __iomem *addr);
+ void (*write_fn)(u32, void __iomem *addr);
+ u32 bytes_to_transfer;
+ u32 bytes_to_receive;
+ u32 rx_bus_width;
+ void (*tx_fifo)(struct xilinx_spi *xqspi);
+ void (*rx_fifo)(struct xilinx_spi *xqspi);
};
+/**
+ * XSPI_FIFO_READ - Generate xspi_read_rx_fifo_* functions
+ * @size: bits_per_word that are read from RX FIFO
+ * @type: C type of value argument
+ *
+ * Generates xspi_read_rx_fifo_* functions used to write
+ * data into RX FIFO for different transaction widths.
+ */
+#define XSPI_FIFO_READ(size, type) \
+static void xspi_read_rx_fifo_##size(struct xilinx_spi *xqspi) \
+{ \
+ int i; \
+ int count = (xqspi->bytes_to_receive > xqspi->buffer_size) ? \
+ xqspi->buffer_size : xqspi->bytes_to_receive; \
+ u32 data; \
+ for (i = 0; i < count; i += (size/8)) { \
+ data = readl_relaxed(xqspi->regs + XSPI_RXD_OFFSET); \
+ if (xqspi->rx_ptr) \
+ ((type *)xqspi->rx_ptr)[i] = (type)data; \
+ } \
+ xqspi->bytes_to_receive -= count; \
+ if (xqspi->rx_ptr) \
+ xqspi->rx_ptr += count; \
+}
+
+/**
+ * XSPI_FIFO_WRITE - Generate xspi_fill_tx_fifo_* functions
+ * @size: bits_per_word that are written into TX FIFO
+ * @type: C type of value argument
+ *
+ * Generates xspi_fill_tx_fifo_* functions used to write
+ * data into TX FIFO for different transaction widths.
+ */
+#define XSPI_FIFO_WRITE(size, type) \
+static void xspi_fill_tx_fifo_##size(struct xilinx_spi *xqspi) \
+{ \
+ int i; \
+ int count = (xqspi->bytes_to_transfer > xqspi->buffer_size) ? \
+ xqspi->buffer_size : xqspi->bytes_to_transfer; \
+ u32 data = 0; \
+ for (i = 0; i < count; i += (size/8)) { \
+ if (xqspi->tx_ptr) \
+ data = (type)((u8 *)xqspi->tx_ptr)[i]; \
+ writel_relaxed(data, (xqspi->regs + XSPI_TXD_OFFSET)); \
+ } \
+ xqspi->bytes_to_transfer -= count; \
+ if (xqspi->tx_ptr) \
+ xqspi->tx_ptr += count; \
+}
+
+XSPI_FIFO_READ(8, u8)
+XSPI_FIFO_READ(16, u16)
+XSPI_FIFO_READ(32, u32)
+XSPI_FIFO_WRITE(8, u8)
+XSPI_FIFO_WRITE(16, u16)
+XSPI_FIFO_WRITE(32, u32)
+
+/**
+ * xspi_write32 - Write a value to the device register little endian
+ * @val: Value to write at the Register offset
+ * @addr: Register offset
+ *
+ * Write data to the paricular SPI register
+ */
static void xspi_write32(u32 val, void __iomem *addr)
{
iowrite32(val, addr);
}
+/**
+ * xspi_read32 - read a value from the device register little endian
+ * @addr: Register offset
+ *
+ * Read data from the paricular SPI register
+ *
+ * Return: return value from the SPI register.
+ */
static unsigned int xspi_read32(void __iomem *addr)
{
return ioread32(addr);
}
+/**
+ * xspi_write32_be - Write a value to the device register big endian
+ * @val: Value to write at the Register offset
+ * @addr: Register offset
+ *
+ * Write data to the paricular SPI register
+ */
static void xspi_write32_be(u32 val, void __iomem *addr)
{
iowrite32be(val, addr);
}
+/**
+ * xspi_read32_be - read a value from the device register big endian
+ * @addr: Register offset
+ *
+ * Read data from the paricular SPI register
+ *
+ * Return: return value from the SPI register.
+ */
static unsigned int xspi_read32_be(void __iomem *addr)
{
return ioread32be(addr);
}
-static void xilinx_spi_tx(struct xilinx_spi *xspi)
-{
- u32 data = 0;
-
- if (!xspi->tx_ptr) {
- xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
- return;
- }
-
- switch (xspi->bytes_per_word) {
- case 1:
- data = *(u8 *)(xspi->tx_ptr);
- break;
- case 2:
- data = *(u16 *)(xspi->tx_ptr);
- break;
- case 4:
- data = *(u32 *)(xspi->tx_ptr);
- break;
- }
-
- xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET);
- xspi->tx_ptr += xspi->bytes_per_word;
-}
-
-static void xilinx_spi_rx(struct xilinx_spi *xspi)
-{
- u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
-
- if (!xspi->rx_ptr)
- return;
-
- switch (xspi->bytes_per_word) {
- case 1:
- *(u8 *)(xspi->rx_ptr) = data;
- break;
- case 2:
- *(u16 *)(xspi->rx_ptr) = data;
- break;
- case 4:
- *(u32 *)(xspi->rx_ptr) = data;
- break;
- }
-
- xspi->rx_ptr += xspi->bytes_per_word;
-}
-
+/**
+ * xspi_init_hw - Initialize the hardware
+ * @xspi: Pointer to the zynqmp_qspi structure
+ *
+ * This function performs the following actions
+ * - Disable and clear all the interrupts
+ * - Enable manual slave select
+ * - Enable the SPI controller
+ */
static void xspi_init_hw(struct xilinx_spi *xspi)
{
void __iomem *regs_base = xspi->regs;
/* Reset the SPI device */
xspi->write_fn(XIPIF_V123B_RESET_MASK,
- regs_base + XIPIF_V123B_RESETR_OFFSET);
- /* Enable the transmit empty interrupt, which we use to determine
+ regs_base + XIPIF_V123B_RESETR_OFFSET);
+ /*
+ * Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
*/
xspi->write_fn(XSPI_INTR_TX_EMPTY,
@@ -176,262 +257,457 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
/* Deselect the slave on the SPI bus */
xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
- /* Disable the transmitter, enable Manual Slave Select Assertion,
- * put SPI controller into master mode, and enable it */
+ /*
+ * Disable the transmitter, enable Manual Slave Select Assertion,
+ * put SPI controller into master mode, and enable it
+ */
xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE |
XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET,
regs_base + XSPI_CR_OFFSET);
}
-static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
+/**
+ * xspi_chipselect - Select or deselect the chip select line
+ * @qspi: Pointer to the spi_device structure
+ * @is_high: Select(0) or deselect (1) the chip select line
+ *
+ */
+static void xspi_chipselect(struct spi_device *qspi, bool is_high)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- u16 cr;
+ struct xilinx_spi *xqspi = spi_master_get_devdata(qspi->master);
u32 cs;
- if (is_on == BITBANG_CS_INACTIVE) {
- /* Deselect the slave on the SPI bus */
- xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET);
- return;
+ if (is_high) {
+ /* Deselect the slave */
+ xqspi->write_fn(xqspi->cs_inactive,
+ xqspi->regs + XSPI_SSR_OFFSET);
+ } else {
+ cs = xqspi->cs_inactive;
+ cs ^= BIT(qspi->chip_select);
+ /* Activate the chip select */
+ xqspi->write_fn(cs, xqspi->regs + XSPI_SSR_OFFSET);
}
+}
- /* Set the SPI clock phase and polarity */
- cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_MODE_MASK;
- if (spi->mode & SPI_CPHA)
- cr |= XSPI_CR_CPHA;
- if (spi->mode & SPI_CPOL)
- cr |= XSPI_CR_CPOL;
- if (spi->mode & SPI_LSB_FIRST)
- cr |= XSPI_CR_LSB_FIRST;
- if (spi->mode & SPI_LOOP)
- cr |= XSPI_CR_LOOP;
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
-
- /* We do not check spi->max_speed_hz here as the SPI clock
- * frequency is not software programmable (the IP block design
- * parameter)
- */
+/**
+ * xilinx_spi_irq - Interrupt service routine of the SPI controller
+ * @irq: IRQ number
+ * @dev_id: Pointer to the xspi structure
+ *
+ * This function handles TX empty only.
+ * On TX empty interrupt this function reads the received data from RX FIFO
+ * and fills the TX FIFO if there is any data remaining to be transferred.
+ *
+ * Return: IRQ_HANDLED when interrupt is handled
+ * IRQ_NONE otherwise.
+ */
+static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct xilinx_spi *xspi = spi_master_get_devdata(dev_id);
+ u32 ipif_isr;
+ int status = IRQ_NONE;
- cs = xspi->cs_inactive;
- cs ^= BIT(spi->chip_select);
+ /* Get the IPIF interrupts, and clear them immediately */
+ ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ if (ipif_isr & XSPI_INTR_TX_EMPTY) {
+ /* Transmission completed */
+ xspi->rx_fifo(xspi);
+ if (xspi->bytes_to_transfer) {
+ /* There is more data to send */
+ xspi->tx_fifo(xspi);
+ }
+ status = IRQ_HANDLED;
+ }
- /* Activate the chip select */
- xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET);
+ if (!xspi->bytes_to_receive && !xspi->bytes_to_transfer) {
+ spi_finalize_current_transfer(master);
+ /* Disable the interrupts here. */
+ xspi->write_fn(0x0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+ }
+
+ return status;
}
-/* spi_bitbang requires custom setup_transfer() to be defined if there is a
- * custom txrx_bufs().
+/**
+ * xilinx_spi_startup_block - Perform a dummy read as a
+ * work around for the startup block issue in the spi controller.
+ * @xspi: Pointer to the xilinx_spi structure
+ * @cs_num: chip select number.
+ *
+ * Perform a dummy read if startup block is enabled in the
+ * spi controller.
+ *
+ * Return: None
*/
-static int xilinx_spi_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t)
+static void xilinx_spi_startup_block(struct xilinx_spi *xspi, u32 cs_num)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ void __iomem *regs_base = xspi->regs;
+ u32 chip_sel, config_reg, status_reg;
- if (spi->mode & SPI_CS_HIGH)
- xspi->cs_inactive &= ~BIT(spi->chip_select);
+ /* Activate the chip select */
+ chip_sel = xspi->cs_inactive;
+ chip_sel ^= BIT(cs_num);
+ xspi->write_fn(chip_sel, regs_base + XSPI_SSR_OFFSET);
+
+ /* Write ReadId to the TXD register */
+ xspi->write_fn(SPI_READ_ID, regs_base + XSPI_TXD_OFFSET);
+ xspi->write_fn(0x0, regs_base + XSPI_TXD_OFFSET);
+ xspi->write_fn(0x0, regs_base + XSPI_TXD_OFFSET);
+
+ config_reg = xspi->read_fn(regs_base + XSPI_CR_OFFSET);
+ /* Enable master transaction */
+ config_reg &= ~XSPI_CR_TRANS_INHIBIT;
+ xspi->write_fn(config_reg, regs_base + XSPI_CR_OFFSET);
+
+ status_reg = xspi->read_fn(regs_base + XSPI_SR_OFFSET);
+ while ((status_reg & XSPI_SR_TX_EMPTY_MASK) == 0)
+ status_reg = xspi->read_fn(regs_base + XSPI_SR_OFFSET);
+
+ /* Disable master transaction */
+ config_reg |= XSPI_CR_TRANS_INHIBIT;
+ xspi->write_fn(config_reg, regs_base + XSPI_CR_OFFSET);
+
+ /* Read the RXD Register */
+ status_reg = xspi->read_fn(regs_base + XSPI_SR_OFFSET);
+ while ((status_reg & XSPI_SR_RX_EMPTY_MASK) == 0) {
+ xspi->read_fn(regs_base + XSPI_RXD_OFFSET);
+ status_reg = xspi->read_fn(regs_base + XSPI_SR_OFFSET);
+ }
+
+ xspi_init_hw(xspi);
+}
+
+/**
+ * xspi_setup_transfer - Configure SPI controller for specified
+ * transfer
+ * @qspi: Pointer to the spi_device structure
+ * @transfer: Pointer to the spi_transfer structure which provides
+ * information about next transfer setup parameters
+ *
+ * Sets the operational mode of QSPI controller for the next QSPI
+ * transfer.
+ *
+ * Return: 0 always
+ */
+static int xspi_setup_transfer(struct spi_device *qspi,
+ struct spi_transfer *transfer)
+{
+ struct xilinx_spi *xqspi = spi_master_get_devdata(qspi->master);
+ u32 config_reg;
+
+ config_reg = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ /* Set the QSPI clock phase and clock polarity */
+ config_reg &= ~(XSPI_CR_CPHA | XSPI_CR_CPOL);
+ if (qspi->mode & SPI_CPHA)
+ config_reg |= XSPI_CR_CPHA;
+ if (qspi->mode & SPI_CPOL)
+ config_reg |= XSPI_CR_CPOL;
+ if (qspi->mode & SPI_LSB_FIRST)
+ config_reg |= XSPI_CR_LSB_FIRST;
+ xqspi->write_fn(config_reg, xqspi->regs + XSPI_CR_OFFSET);
+
+ if (qspi->mode & SPI_CS_HIGH)
+ xqspi->cs_inactive &= ~BIT(qspi->chip_select);
else
- xspi->cs_inactive |= BIT(spi->chip_select);
+ xqspi->cs_inactive |= BIT(qspi->chip_select);
return 0;
}
-static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+/**
+ * xspi_setup - Configure the SPI controller
+ * @qspi: Pointer to the spi_device structure
+ *
+ * Sets the operational mode of QSPI controller for the next QSPI
+ * transfer.
+ *
+ * Return: 0 on success; error value otherwise.
+ */
+static int xspi_setup(struct spi_device *qspi)
+{
+ int ret;
+ struct xilinx_spi *xqspi = spi_master_get_devdata(qspi->master);
+
+ if (qspi->master->busy)
+ return -EBUSY;
+
+ ret = pm_runtime_get_sync(xqspi->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = xspi_setup_transfer(qspi, NULL);
+ pm_runtime_put_sync(xqspi->dev);
+
+ return ret;
+}
+
+/**
+ * xspi_start_transfer - Initiates the SPI transfer
+ * @master: Pointer to the spi_master structure which provides
+ * information about the controller.
+ * @qspi: Pointer to the spi_device structure
+ * @transfer: Pointer to the spi_transfer structure which provide information
+ * about next transfer parameters
+ *
+ * This function fills the TX FIFO, starts the SPI transfer, and waits for the
+ * transfer to be completed.
+ *
+ * Return: Number of bytes transferred in the last transfer
+ */
+
+static int xspi_start_transfer(struct spi_master *master,
+ struct spi_device *qspi,
+ struct spi_transfer *transfer)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- int remaining_words; /* the number of words left to transfer */
- bool use_irq = false;
- u16 cr = 0;
-
- /* We get here with transmitter inhibited */
-
- xspi->tx_ptr = t->tx_buf;
- xspi->rx_ptr = t->rx_buf;
- remaining_words = t->len / xspi->bytes_per_word;
-
- if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
- u32 isr;
- use_irq = true;
- /* Inhibit irq to avoid spurious irqs on tx_empty*/
- cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
- xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
- xspi->regs + XSPI_CR_OFFSET);
- /* ACK old irqs (if any) */
- isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
- if (isr)
- xspi->write_fn(isr,
- xspi->regs + XIPIF_V123B_IISR_OFFSET);
- /* Enable the global IPIF interrupt */
- xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
- xspi->regs + XIPIF_V123B_DGIER_OFFSET);
- reinit_completion(&xspi->done);
+ struct xilinx_spi *xqspi = spi_master_get_devdata(master);
+ u32 cr;
+
+ xqspi->tx_ptr = transfer->tx_buf;
+ xqspi->rx_ptr = transfer->rx_buf;
+
+ if (transfer->dummy) {
+ xqspi->bytes_to_transfer = (transfer->len - (transfer->dummy/8))
+ + ((transfer->dummy/8) *
+ xqspi->rx_bus_width);
+ xqspi->bytes_to_receive = (transfer->len - (transfer->dummy/8))
+ + ((transfer->dummy/8) *
+ xqspi->rx_bus_width);
+ } else {
+ xqspi->bytes_to_transfer = transfer->len;
+ xqspi->bytes_to_receive = transfer->len;
}
- while (remaining_words) {
- int n_words, tx_words, rx_words;
- u32 sr;
- int stalled;
+ xspi_setup_transfer(qspi, transfer);
+ cr = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ /* Enable master transaction inhibit */
+ cr |= XSPI_CR_TRANS_INHIBIT;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
+ xqspi->tx_fifo(xqspi);
+ /* Disable master transaction inhibit */
+ cr &= ~XSPI_CR_TRANS_INHIBIT;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
+ xqspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+ xqspi->regs + XIPIF_V123B_DGIER_OFFSET);
+
+ return transfer->len;
+}
- n_words = min(remaining_words, xspi->buffer_size);
+/**
+ * xspi_prepare_transfer_hardware - Prepares hardware for transfer.
+ * @master: Pointer to the spi_master structure which provides
+ * information about the controller.
+ *
+ * This function enables SPI master controller.
+ *
+ * Return: 0 on success; error value otherwise
+ */
+static int xspi_prepare_transfer_hardware(struct spi_master *master)
+{
+ struct xilinx_spi *xqspi = spi_master_get_devdata(master);
- tx_words = n_words;
- while (tx_words--)
- xilinx_spi_tx(xspi);
+ u32 cr;
+ int ret;
- /* Start the transfer by not inhibiting the transmitter any
- * longer
- */
+ ret = pm_runtime_get_sync(xqspi->dev);
+ if (ret < 0)
+ return ret;
- if (use_irq) {
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
- wait_for_completion(&xspi->done);
- /* A transmit has just completed. Process received data
- * and check for more data to transmit. Always inhibit
- * the transmitter while the Isr refills the transmit
- * register/FIFO, or make sure it is stopped if we're
- * done.
- */
- xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
- xspi->regs + XSPI_CR_OFFSET);
- sr = XSPI_SR_TX_EMPTY_MASK;
- } else
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
-
- /* Read out all the data from the Rx FIFO */
- rx_words = n_words;
- stalled = 10;
- while (rx_words) {
- if (rx_words == n_words && !(stalled--) &&
- !(sr & XSPI_SR_TX_EMPTY_MASK) &&
- (sr & XSPI_SR_RX_EMPTY_MASK)) {
- dev_err(&spi->dev,
- "Detected stall. Check C_SPI_MODE and C_SPI_MEMORY\n");
- xspi_init_hw(xspi);
- return -EIO;
- }
-
- if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) {
- xilinx_spi_rx(xspi);
- rx_words--;
- continue;
- }
-
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- if (!(sr & XSPI_SR_RX_EMPTY_MASK)) {
- xilinx_spi_rx(xspi);
- rx_words--;
- }
- }
+ cr = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ cr |= XSPI_CR_ENABLE;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
+
+ return 0;
+}
+
+/**
+ * xspi_unprepare_transfer_hardware - Relaxes hardware after transfer
+ * @master: Pointer to the spi_master structure which provides
+ * information about the controller.
+ *
+ * This function disables the SPI master controller.
+ *
+ * Return: Always 0
+ */
+static int xspi_unprepare_transfer_hardware(struct spi_master *master)
+{
+ struct xilinx_spi *xqspi = spi_master_get_devdata(master);
+ u32 cr;
+
+ cr = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ cr &= ~XSPI_CR_ENABLE;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
+
+ pm_runtime_put_sync(xqspi->dev);
+
+ return 0;
+}
+
+/**
+ * xilinx_spi_runtime_resume - Runtime resume method for the SPI driver
+ * @dev: Address of the platform_device structure
+ *
+ * This function enables the clocks
+ *
+ * Return: 0 on success and error value on error
+ */
+static int __maybe_unused xilinx_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct xilinx_spi *xspi = spi_master_get_devdata(master);
+ int ret;
- remaining_words -= n_words;
+ ret = clk_enable(xspi->axi_clk);
+ if (ret) {
+ dev_err(dev, "Can not enable AXI clock\n");
+ return ret;
}
- if (use_irq) {
- xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+ ret = clk_enable(xspi->axi4_clk);
+ if (ret) {
+ dev_err(dev, "Can not enable AXI4 clock\n");
+ goto clk_disable_axi_clk;
}
- return t->len;
+ ret = clk_enable(xspi->spi_clk);
+ if (ret) {
+ dev_err(dev, "Can not enable SPI clock\n");
+ goto clk_disable_axi4_clk;
+ }
+
+ return 0;
+
+clk_disable_axi4_clk:
+ clk_disable(xspi->axi4_clk);
+clk_disable_axi_clk:
+ clk_disable(xspi->axi_clk);
+
+ return ret;
}
+/**
+ * xilinx_spi_runtime_suspend - Runtime suspend method for the SPI driver
+ * @dev: Address of the platform_device structure
+ *
+ * This function disables the clocks
+ *
+ * Return: Always 0
+ */
+static int __maybe_unused xilinx_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct xilinx_spi *xspi = spi_master_get_devdata(master);
+
+ clk_disable(xspi->axi_clk);
+ clk_disable(xspi->axi4_clk);
+ clk_disable(xspi->spi_clk);
+
+ return 0;
+}
-/* This driver supports single master mode only. Hence Tx FIFO Empty
- * is the only interrupt we care about.
- * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
- * Fault are not to happen.
+/**
+ * xilinx_spi_resume - Resume method for the SPI driver
+ * @dev: Address of the platform_device structure
+ *
+ * The function starts the SPI driver queue and initializes the SPI
+ * controller
+ *
+ * Return: 0 on success; error value otherwise
*/
-static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
+static int __maybe_unused xilinx_spi_resume(struct device *dev)
{
- struct xilinx_spi *xspi = dev_id;
- u32 ipif_isr;
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct xilinx_spi *xspi = spi_master_get_devdata(master);
+ int ret = 0;
- /* Get the IPIF interrupts, and clear them immediately */
- ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
- xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ if (!pm_runtime_suspended(dev)) {
+ ret = xilinx_spi_runtime_resume(dev);
+ if (ret < 0)
+ return ret;
+ }
- if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
- complete(&xspi->done);
- return IRQ_HANDLED;
+ ret = spi_master_resume(master);
+ if (ret < 0) {
+ clk_disable(xspi->axi_clk);
+ clk_disable(xspi->axi4_clk);
+ clk_disable(xspi->spi_clk);
}
- return IRQ_NONE;
+ return ret;
}
-static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
+
+/**
+ * xilinx_spi_suspend - Suspend method for the SPI driver
+ * @dev: Address of the platform_device structure
+ *
+ * This function stops the SPI driver queue and disables the SPI controller
+ *
+ * Return: Always 0
+ */
+static int __maybe_unused xilinx_spi_suspend(struct device *dev)
{
- u8 sr;
- int n_words = 0;
+ struct spi_master *master = dev_get_drvdata(dev);
+ int ret = 0;
- /*
- * Before the buffer_size detection we reset the core
- * to make sure we start with a clean state.
- */
- xspi->write_fn(XIPIF_V123B_RESET_MASK,
- xspi->regs + XIPIF_V123B_RESETR_OFFSET);
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ if (!pm_runtime_suspended(dev))
+ xilinx_spi_runtime_suspend(dev);
- /* Fill the Tx FIFO with as many words as possible */
- do {
- xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- n_words++;
- } while (!(sr & XSPI_SR_TX_FULL_MASK));
+ xspi_unprepare_transfer_hardware(master);
- return n_words;
+ return ret;
}
-static const struct of_device_id xilinx_spi_of_match[] = {
- { .compatible = "xlnx,axi-quad-spi-1.00.a", },
- { .compatible = "xlnx,xps-spi-2.00.a", },
- { .compatible = "xlnx,xps-spi-2.00.b", },
- {}
+static const struct dev_pm_ops xilinx_spi_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(xilinx_spi_runtime_suspend,
+ xilinx_spi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(xilinx_spi_suspend, xilinx_spi_resume)
};
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+/**
+ * xilinx_spi_probe - Probe method for the SPI driver
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This function initializes the driver data structures and the hardware.
+ *
+ * Return: 0 on success; error value otherwise
+ */
static int xilinx_spi_probe(struct platform_device *pdev)
{
struct xilinx_spi *xspi;
- struct xspi_platform_data *pdata;
struct resource *res;
int ret, num_cs = 0, bits_per_word = 8;
+ u32 cs_num;
struct spi_master *master;
- u32 tmp;
- u8 i;
-
- pdata = dev_get_platdata(&pdev->dev);
- if (pdata) {
- num_cs = pdata->num_chipselect;
- bits_per_word = pdata->bits_per_word;
- } else {
- of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
- &num_cs);
- }
+ struct device_node *nc;
+ u32 tmp, rx_bus_width, fifo_size;
+ bool startup_block;
- if (!num_cs) {
- dev_err(&pdev->dev,
- "Missing slave select configuration data\n");
- return -EINVAL;
- }
+ of_property_read_u32(pdev->dev.of_node, "num-cs",
+ &num_cs);
+ if (!num_cs)
+ num_cs = 1;
if (num_cs > XILINX_SPI_MAX_CS) {
dev_err(&pdev->dev, "Invalid number of spi slaves\n");
return -EINVAL;
}
+ startup_block = of_property_read_bool(pdev->dev.of_node,
+ "xlnx,startup-block");
+
master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
if (!master)
return -ENODEV;
- /* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
- SPI_CS_HIGH;
-
xspi = spi_master_get_devdata(master);
- xspi->cs_inactive = 0xffffffff;
- xspi->bitbang.master = master;
- xspi->bitbang.chipselect = xilinx_spi_chipselect;
- xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
- xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
- init_completion(&xspi->done);
-
+ master->dev.of_node = pdev->dev.of_node;
+ platform_set_drvdata(pdev, master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xspi->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xspi->regs)) {
@@ -439,20 +715,104 @@ static int xilinx_spi_probe(struct platform_device *pdev)
goto put_master;
}
- master->bus_num = pdev->id;
- master->num_chipselect = num_cs;
- master->dev.of_node = pdev->dev.of_node;
+ ret = of_property_read_u32(pdev->dev.of_node, "fifo-size",
+ &fifo_size);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Missing fifo size\n");
+ return -EINVAL;
+ }
+ of_property_read_u32(pdev->dev.of_node, "bits-per-word",
+ &bits_per_word);
+
+ xspi->rx_bus_width = XSPI_ONE_BITS_PER_WORD;
+ for_each_available_child_of_node(pdev->dev.of_node, nc) {
+ if (startup_block) {
+ ret = of_property_read_u32(nc, "reg",
+ &cs_num);
+ if (ret < 0)
+ return -EINVAL;
+ }
+ ret = of_property_read_u32(nc, "spi-rx-bus-width",
+ &rx_bus_width);
+ if (!ret) {
+ xspi->rx_bus_width = rx_bus_width;
+ break;
+ }
+ }
+
+ xspi->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
+ if (IS_ERR(xspi->axi_clk)) {
+ if (PTR_ERR(xspi->axi_clk) != -ENOENT) {
+ ret = PTR_ERR(xspi->axi_clk);
+ goto put_master;
+ }
+
+ /*
+ * Clock framework support is optional, continue on,
+ * anyways if we don't find a matching clock
+ */
+ xspi->axi_clk = NULL;
+ }
+
+ ret = clk_prepare(xspi->axi_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to prepare AXI clock\n");
+ goto put_master;
+ }
+
+ xspi->axi4_clk = devm_clk_get(&pdev->dev, "axi4_clk");
+ if (IS_ERR(xspi->axi4_clk)) {
+ if (PTR_ERR(xspi->axi4_clk) != -ENOENT) {
+ ret = PTR_ERR(xspi->axi4_clk);
+ goto clk_unprepare_axi_clk;
+ }
+
+ /*
+ * Clock framework support is optional, continue on,
+ * anyways if we don't find a matching clock
+ */
+ xspi->axi4_clk = NULL;
+ }
+
+ ret = clk_prepare(xspi->axi4_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to prepare AXI4 clock\n");
+ goto clk_unprepare_axi_clk;
+ }
+
+ xspi->spi_clk = devm_clk_get(&pdev->dev, "spi_clk");
+ if (IS_ERR(xspi->spi_clk)) {
+ if (PTR_ERR(xspi->spi_clk) != -ENOENT) {
+ ret = PTR_ERR(xspi->spi_clk);
+ goto clk_unprepare_axi4_clk;
+ }
+
+ /*
+ * Clock framework support is optional, continue on,
+ * anyways if we don't find a matching clock
+ */
+ xspi->spi_clk = NULL;
+ }
+
+ ret = clk_prepare(xspi->spi_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to prepare SPI clock\n");
+ goto clk_unprepare_axi4_clk;
+ }
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto clk_unprepare_all;
+
+ xspi->dev = &pdev->dev;
- /*
- * Detect endianess on the IP via loop bit in CR. Detection
- * must be done before reset is sent because incorrect reset
- * value generates error interrupt.
- * Setup little endian helper functions first and try to use them
- * and check if bit was correctly setup or not.
- */
xspi->read_fn = xspi_read32;
xspi->write_fn = xspi_write32;
-
+ /* Detect endianness on the IP via loop bit in CR register*/
xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET);
tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
tmp &= XSPI_CR_LOOP;
@@ -461,62 +821,112 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->write_fn = xspi_write32_be;
}
- master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
- xspi->bytes_per_word = bits_per_word / 8;
- xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
-
+ xspi->buffer_size = fifo_size;
xspi->irq = platform_get_irq(pdev, 0);
if (xspi->irq < 0 && xspi->irq != -ENXIO) {
ret = xspi->irq;
- goto put_master;
+ goto clk_unprepare_all;
} else if (xspi->irq >= 0) {
/* Register for SPI Interrupt */
- ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
- dev_name(&pdev->dev), xspi);
+ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq,
+ 0, dev_name(&pdev->dev), master);
if (ret)
- goto put_master;
+ goto clk_unprepare_all;
}
/* SPI controller initializations */
xspi_init_hw(xspi);
- ret = spi_bitbang_start(&xspi->bitbang);
- if (ret) {
- dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
- goto put_master;
+ pm_runtime_put(&pdev->dev);
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = num_cs;
+ master->setup = xspi_setup;
+ master->set_cs = xspi_chipselect;
+ master->transfer_one = xspi_start_transfer;
+ master->prepare_transfer_hardware = xspi_prepare_transfer_hardware;
+ master->unprepare_transfer_hardware = xspi_unprepare_transfer_hardware;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+ xspi->bytes_per_word = bits_per_word / 8;
+ xspi->tx_fifo = xspi_fill_tx_fifo_8;
+ xspi->rx_fifo = xspi_read_rx_fifo_8;
+ if (xspi->rx_bus_width == XSPI_RX_ONE_WIRE) {
+ if (xspi->bytes_per_word == XSPI_TWO_BITS_PER_WORD) {
+ xspi->tx_fifo = xspi_fill_tx_fifo_16;
+ xspi->rx_fifo = xspi_read_rx_fifo_16;
+ } else if (xspi->bytes_per_word == XSPI_FOUR_BITS_PER_WORD) {
+ xspi->tx_fifo = xspi_fill_tx_fifo_32;
+ xspi->rx_fifo = xspi_read_rx_fifo_32;
+ }
+ } else if (xspi->rx_bus_width == XSPI_RX_FOUR_WIRE) {
+ master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
+ } else {
+ dev_err(&pdev->dev, "Dual Mode not supported\n");
+ goto clk_unprepare_all;
}
+ xspi->cs_inactive = 0xffffffff;
- dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
- (unsigned long long)res->start, xspi->regs, xspi->irq);
+ /*
+ * This is the work around for the startup block issue in
+ * the spi controller. SPI clock is passing through STARTUP
+ * block to FLASH. STARTUP block don't provide clock as soon
+ * as QSPI provides command. So first command fails.
+ */
+ if (startup_block)
+ xilinx_spi_startup_block(xspi, cs_num);
- if (pdata) {
- for (i = 0; i < pdata->num_devices; i++)
- spi_new_device(master, pdata->devices + i);
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(&pdev->dev, "spi_register_master failed\n");
+ goto clk_unprepare_all;
}
- platform_set_drvdata(pdev, master);
- return 0;
+ return ret;
+clk_unprepare_all:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ clk_unprepare(xspi->spi_clk);
+clk_unprepare_axi4_clk:
+ clk_unprepare(xspi->axi4_clk);
+clk_unprepare_axi_clk:
+ clk_unprepare(xspi->axi_clk);
put_master:
spi_master_put(master);
return ret;
}
+/**
+ * xilinx_spi_remove - Remove method for the SPI driver
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This function is called if a device is physically removed from the system or
+ * if the driver module is being unloaded. It frees all resources allocated to
+ * the device.
+ *
+ * Return: 0 Always
+ */
static int xilinx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct xilinx_spi *xspi = spi_master_get_devdata(master);
void __iomem *regs_base = xspi->regs;
- spi_bitbang_stop(&xspi->bitbang);
-
/* Disable all the interrupts just in case */
xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
/* Disable the global IPIF interrupt */
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
- spi_master_put(xspi->bitbang.master);
+ pm_runtime_disable(&pdev->dev);
+
+ clk_disable_unprepare(xspi->axi_clk);
+ clk_disable_unprepare(xspi->axi4_clk);
+ clk_disable_unprepare(xspi->spi_clk);
+
+ spi_unregister_master(master);
return 0;
}
@@ -524,12 +934,21 @@ static int xilinx_spi_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" XILINX_SPI_NAME);
+static const struct of_device_id xilinx_spi_of_match[] = {
+ { .compatible = "xlnx,axi-quad-spi-1.00.a", },
+ { .compatible = "xlnx,xps-spi-2.00.a", },
+ { .compatible = "xlnx,xps-spi-2.00.b", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+
static struct platform_driver xilinx_spi_driver = {
.probe = xilinx_spi_probe,
.remove = xilinx_spi_remove,
.driver = {
.name = XILINX_SPI_NAME,
.of_match_table = xilinx_spi_of_match,
+ .pm = &xilinx_spi_dev_pm_ops,
},
};
module_platform_driver(xilinx_spi_driver);
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index c6bee67decb5..2041d5dcf294 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -129,6 +129,9 @@
* @rxbuf: Pointer to the RX buffer
* @tx_bytes: Number of bytes left to transfer
* @rx_bytes: Number of bytes left to receive
+ * @is_dual: Flag to indicate whether dual flash memories are used
+ * @is_instr: Flag to indicate if transfer contains an instruction
+ * (Used in dual parallel configuration)
* @data_completion: completion structure
*/
struct zynq_qspi {
@@ -141,6 +144,8 @@ struct zynq_qspi {
u8 *rxbuf;
int tx_bytes;
int rx_bytes;
+ u32 is_dual;
+ u8 is_instr;
struct completion data_completion;
};
@@ -213,6 +218,14 @@ static void zynq_qspi_init_hw(struct zynq_qspi *xqspi)
zynq_qspi_write(xqspi, ZYNQ_QSPI_TX_THRESH_OFFSET,
ZYNQ_QSPI_TX_THRESHOLD);
+ if (xqspi->is_dual)
+ /* Enable two memories on separate buses */
+ zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET,
+ (ZYNQ_QSPI_LCFG_TWO_MEM_MASK |
+ ZYNQ_QSPI_LCFG_SEP_BUS_MASK |
+ (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) |
+ ZYNQ_QSPI_FAST_READ_QOUT_CODE));
+
zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET,
ZYNQ_QSPI_ENABLE_ENABLE_MASK);
}
@@ -236,15 +249,23 @@ static bool zynq_qspi_supports_op(struct spi_mem *mem,
* zynq_qspi_rxfifo_op - Read 1..4 bytes from RxFIFO to RX buffer
* @xqspi: Pointer to the zynq_qspi structure
* @size: Number of bytes to be read (1..4)
+ *
+ * Note: In case of dual parallel connection, even number of bytes are read
+ * when odd bytes are requested to avoid transfer of a nibble to each flash.
+ * The receive buffer though, is populated with the number of bytes requested.
*/
static void zynq_qspi_rxfifo_op(struct zynq_qspi *xqspi, unsigned int size)
{
+ unsigned int xsize;
u32 data;
data = zynq_qspi_read(xqspi, ZYNQ_QSPI_RXD_OFFSET);
if (xqspi->rxbuf) {
- memcpy(xqspi->rxbuf, ((u8 *)&data) + 4 - size, size);
+ xsize = size;
+ if (xqspi->is_dual && !xqspi->is_instr && (size % 2))
+ xsize++;
+ memcpy(xqspi->rxbuf, ((u8 *)&data) + 4 - xsize, size);
xqspi->rxbuf += size;
}
@@ -257,12 +278,19 @@ static void zynq_qspi_rxfifo_op(struct zynq_qspi *xqspi, unsigned int size)
* zynq_qspi_txfifo_op - Write 1..4 bytes from TX buffer to TxFIFO
* @xqspi: Pointer to the zynq_qspi structure
* @size: Number of bytes to be written (1..4)
+ *
+ * In dual parallel configuration, when read/write data operations
+ * are performed, odd data bytes have to be converted to even to
+ * avoid a nibble (of data when programming / dummy when reading)
+ * going to individual flash devices, where a byte is expected.
+ * This check is only for data and will not apply for commands.
*/
static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
{
static const unsigned int offset[4] = {
ZYNQ_QSPI_TXD_00_01_OFFSET, ZYNQ_QSPI_TXD_00_10_OFFSET,
ZYNQ_QSPI_TXD_00_11_OFFSET, ZYNQ_QSPI_TXD_00_00_OFFSET };
+ unsigned int xsize;
u32 data;
if (xqspi->txbuf) {
@@ -274,7 +302,11 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
}
xqspi->tx_bytes -= size;
- zynq_qspi_write(xqspi, offset[size - 1], data);
+
+ xsize = size;
+ if (xqspi->is_dual && !xqspi->is_instr && (size % 2))
+ xsize++;
+ zynq_qspi_write(xqspi, offset[xsize - 1], data);
}
/**
@@ -295,6 +327,7 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
config_reg |= (((~(BIT(spi->chip_select))) <<
ZYNQ_QSPI_SS_SHIFT) &
ZYNQ_QSPI_CONFIG_SSCTRL_MASK);
+ xqspi->is_instr = 1;
} else {
config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
}
@@ -637,6 +670,12 @@ static int zynq_qspi_probe(struct platform_device *pdev)
goto remove_master;
}
+ if (of_property_read_u32(pdev->dev.of_node, "is-dual",
+ &xqspi->is_dual)) {
+ dev_warn(&pdev->dev, "couldn't determine configuration info");
+ dev_warn(&pdev->dev, "about dual memories. defaulting to single memory\n");
+ }
+
xqspi->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(xqspi->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index ddf408a6b60c..2b794f57964d 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -33,6 +34,7 @@
#define GQSPI_RXD_OFST 0x00000120
#define GQSPI_TX_THRESHOLD_OFST 0x00000128
#define GQSPI_RX_THRESHOLD_OFST 0x0000012C
+#define IOU_TAPDLY_BYPASS_OFST 0x0000003C
#define GQSPI_LPBK_DLY_ADJ_OFST 0x00000138
#define GQSPI_GEN_FIFO_OFST 0x00000140
#define GQSPI_SEL_OFST 0x00000144
@@ -47,6 +49,7 @@
#define GQSPI_QSPIDMA_DST_I_MASK_OFST 0x00000820
#define GQSPI_QSPIDMA_DST_ADDR_OFST 0x00000800
#define GQSPI_QSPIDMA_DST_ADDR_MSB_OFST 0x00000828
+#define GQSPI_DATA_DLY_ADJ_OFST 0x000001F8
/* GQSPI register bit masks */
#define GQSPI_SEL_MASK 0x00000001
@@ -132,12 +135,44 @@
#define GQSPI_SELECT_MODE_QUADSPI 0x4
#define GQSPI_DMA_UNALIGN 0x3
#define GQSPI_DEFAULT_NUM_CS 1 /* Default number of chip selects */
+#define GQSPI_RX_BUS_WIDTH_QUAD 0x4
+#define GQSPI_RX_BUS_WIDTH_DUAL 0x2
+#define GQSPI_RX_BUS_WIDTH_SINGLE 0x1
+#define GQSPI_TX_BUS_WIDTH_QUAD 0x4
+#define GQSPI_TX_BUS_WIDTH_DUAL 0x2
+#define GQSPI_TX_BUS_WIDTH_SINGLE 0x1
+#define GQSPI_LPBK_DLY_ADJ_LPBK_SHIFT 5
+#define GQSPI_LPBK_DLY_ADJ_DLY_1 0x2
+#define GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT 3
+#define GQSPI_LPBK_DLY_ADJ_DLY_0 0x3
+#define GQSPI_USE_DATA_DLY 0x1
+#define GQSPI_USE_DATA_DLY_SHIFT 31
+#define GQSPI_DATA_DLY_ADJ_VALUE 0x2
+#define GQSPI_DATA_DLY_ADJ_SHIFT 28
+#define TAP_DLY_BYPASS_LQSPI_RX_VALUE 0x1
+#define TAP_DLY_BYPASS_LQSPI_RX_SHIFT 2
+
+/* set to differentiate versal from zynqmp, 1=versal, 0=zynqmp */
+#define QSPI_QUIRK_HAS_TAPDELAY BIT(0)
+
+#define GQSPI_FREQ_40MHZ 40000000
+#define GQSPI_FREQ_100MHZ 100000000
+#define GQSPI_FREQ_150MHZ 150000000
+#define IOU_TAPDLY_BYPASS_MASK 0x7
#define SPI_AUTOSUSPEND_TIMEOUT 3000
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
static const struct zynqmp_eemi_ops *eemi_ops;
/**
+ * struct zynq_platform_data - zynqmp qspi platform data structure
+ * @quirks: Flags is used to identify the platform
+ */
+struct qspi_platform_data {
+ u32 quirks;
+};
+
+/**
* struct zynqmp_qspi - Defines qspi driver instance
* @regs: Virtual address of the QSPI controller registers
* @refclk: Pointer to the peripheral clock
@@ -152,8 +187,14 @@ static const struct zynqmp_eemi_ops *eemi_ops;
* @genfifobus: Used to select the upper or lower bus
* @dma_rx_bytes: Remaining bytes to receive by DMA mode
* @dma_addr: DMA address after mapping the kernel buffer
+ * @tx_bus_width: Used to represent number of data wires for tx
+ * @rx_bus_width: Used to represent number of data wires
* @genfifoentry: Used for storing the genfifoentry instruction.
+ * @isinstr: To determine whether the transfer is instruction
* @mode: Defines the mode in which QSPI is operating
+ * @speed_hz: Current SPI bus clock speed in hz
+ * @io_mode: Defines the operating mode, either IO or dma
+ * @has_tapdelay: Used for tapdelay register available in qspi
*/
struct zynqmp_qspi {
void __iomem *regs;
@@ -169,14 +210,22 @@ struct zynqmp_qspi {
u32 genfifobus;
u32 dma_rx_bytes;
dma_addr_t dma_addr;
+ u32 rx_bus_width;
+ u32 tx_bus_width;
u32 genfifoentry;
+ bool isinstr;
enum mode_type mode;
+ u32 speed_hz;
+ bool io_mode;
+ bool has_tapdelay;
};
/**
- * zynqmp_gqspi_read: For GQSPI controller read operation
+ * zynqmp_gqspi_read - For GQSPI controller read operation
* @xqspi: Pointer to the zynqmp_qspi structure
* @offset: Offset from where to read
+ *
+ * Return: Value read from the qspi register
*/
static u32 zynqmp_gqspi_read(struct zynqmp_qspi *xqspi, u32 offset)
{
@@ -184,7 +233,7 @@ static u32 zynqmp_gqspi_read(struct zynqmp_qspi *xqspi, u32 offset)
}
/**
- * zynqmp_gqspi_write: For GQSPI controller write operation
+ * zynqmp_gqspi_write - For GQSPI controller write operation
* @xqspi: Pointer to the zynqmp_qspi structure
* @offset: Offset where to write
* @val: Value to be written
@@ -196,10 +245,10 @@ static inline void zynqmp_gqspi_write(struct zynqmp_qspi *xqspi, u32 offset,
}
/**
- * zynqmp_gqspi_selectslave: For selection of slave device
+ * zynqmp_gqspi_selectslave - For selection of slave device
* @instanceptr: Pointer to the zynqmp_qspi structure
- * @flashcs: For chip select
- * @flashbus: To check which bus is selected- upper or lower
+ * @slavecs: For chip select
+ * @slavebus: To check which bus is selected- upper or lower
*/
static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
u8 slavecs, u8 slavebus)
@@ -243,7 +292,76 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
}
/**
- * zynqmp_qspi_init_hw: Initialize the hardware
+ * zynqmp_qspi_set_tapdelay - To configure qspi tap delays
+ * @xqspi: Pointer to the zynqmp_qspi structure
+ * @baudrateval: Buadrate to configure
+ */
+static void zynqmp_qspi_set_tapdelay(struct zynqmp_qspi *xqspi, u32 baudrateval)
+{
+ u32 tapdlybypass = 0, lpbkdlyadj = 0, datadlyadj = 0, clk_rate;
+ u32 reqhz = 0;
+
+ if (!eemi_ops->ioctl)
+ return;
+
+ clk_rate = clk_get_rate(xqspi->refclk);
+ reqhz = (clk_rate / (GQSPI_BAUD_DIV_SHIFT << baudrateval));
+
+ if (!xqspi->has_tapdelay) {
+ if (reqhz <= GQSPI_FREQ_40MHZ) {
+ eemi_ops->ioctl(NODE_QSPI, IOCTL_SET_TAPDELAY_BYPASS,
+ PM_TAPDELAY_QSPI,
+ PM_TAPDELAY_BYPASS_ENABLE,
+ NULL);
+ } else if (reqhz <= GQSPI_FREQ_100MHZ) {
+ eemi_ops->ioctl(NODE_QSPI, IOCTL_SET_TAPDELAY_BYPASS,
+ PM_TAPDELAY_QSPI,
+ PM_TAPDELAY_BYPASS_ENABLE,
+ NULL);
+ lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK);
+ datadlyadj |= ((GQSPI_USE_DATA_DLY <<
+ GQSPI_USE_DATA_DLY_SHIFT)
+ | (GQSPI_DATA_DLY_ADJ_VALUE <<
+ GQSPI_DATA_DLY_ADJ_SHIFT));
+ } else if (reqhz <= GQSPI_FREQ_150MHZ) {
+ lpbkdlyadj |= GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK;
+ }
+ } else {
+ if (reqhz <= GQSPI_FREQ_40MHZ) {
+ tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT);
+ } else if (reqhz <= GQSPI_FREQ_100MHZ) {
+ tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT);
+ lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK);
+ datadlyadj |= ((GQSPI_USE_DATA_DLY <<
+ GQSPI_USE_DATA_DLY_SHIFT)
+ | (GQSPI_DATA_DLY_ADJ_VALUE <<
+ GQSPI_DATA_DLY_ADJ_SHIFT));
+ } else if (reqhz <= GQSPI_FREQ_150MHZ) {
+ lpbkdlyadj |= GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK;
+ }
+ zynqmp_gqspi_write(xqspi,
+ IOU_TAPDLY_BYPASS_OFST, tapdlybypass);
+ }
+
+ zynqmp_gqspi_write(xqspi, GQSPI_LPBK_DLY_ADJ_OFST, lpbkdlyadj);
+ zynqmp_gqspi_write(xqspi, GQSPI_DATA_DLY_ADJ_OFST, datadlyadj);
+}
+
+static u32 zynqmp_disable_intr(struct zynqmp_qspi *xqspi)
+{
+ u32 value;
+
+ zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK);
+ value = zynqmp_gqspi_read(xqspi, GQSPI_IMASK_OFST);
+ zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK);
+
+ return value;
+}
+
+/**
+ * zynqmp_qspi_init_hw - Initialize the hardware
* @xqspi: Pointer to the zynqmp_qspi structure
*
* The default settings of the QSPI controller's configurable parameters on
@@ -267,9 +385,7 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi)
/* Select the GQSPI mode */
zynqmp_gqspi_write(xqspi, GQSPI_SEL_OFST, GQSPI_SEL_MASK);
/* Clear and disable interrupts */
- zynqmp_gqspi_write(xqspi, GQSPI_ISR_OFST,
- zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST) |
- GQSPI_ISR_WR_TO_CLR_MASK);
+ zynqmp_disable_intr(xqspi);
/* Clear the DMA STS */
zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_I_STS_OFST,
zynqmp_gqspi_read(xqspi,
@@ -321,17 +437,18 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi)
zynqmp_gqspi_selectslave(xqspi,
GQSPI_SELECT_FLASH_CS_LOWER,
GQSPI_SELECT_FLASH_BUS_LOWER);
- /* Initialize DMA */
- zynqmp_gqspi_write(xqspi,
+ if (!xqspi->io_mode) {
+ /* Initialize DMA */
+ zynqmp_gqspi_write(xqspi,
GQSPI_QSPIDMA_DST_CTRL_OFST,
GQSPI_QSPIDMA_DST_CTRL_RESET_VAL);
-
+ }
/* Enable the GQSPI */
zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK);
}
/**
- * zynqmp_qspi_copy_read_data: Copy data to RX buffer
+ * zynqmp_qspi_copy_read_data - Copy data to RX buffer
* @xqspi: Pointer to the zynqmp_qspi structure
* @data: The variable where data is stored
* @size: Number of bytes to be copied from data to RX buffer
@@ -345,7 +462,7 @@ static void zynqmp_qspi_copy_read_data(struct zynqmp_qspi *xqspi,
}
/**
- * zynqmp_prepare_transfer_hardware: Prepares hardware for transfer.
+ * zynqmp_prepare_transfer_hardware - Prepares hardware for transfer.
* @master: Pointer to the spi_master structure which provides
* information about the controller.
*
@@ -362,7 +479,7 @@ static int zynqmp_prepare_transfer_hardware(struct spi_master *master)
}
/**
- * zynqmp_unprepare_transfer_hardware: Relaxes hardware after transfer
+ * zynqmp_unprepare_transfer_hardware - Relaxes hardware after transfer
* @master: Pointer to the spi_master structure which provides
* information about the controller.
*
@@ -379,7 +496,7 @@ static int zynqmp_unprepare_transfer_hardware(struct spi_master *master)
}
/**
- * zynqmp_qspi_chipselect: Select or deselect the chip select line
+ * zynqmp_qspi_chipselect - Select or deselect the chip select line
* @qspi: Pointer to the spi_device structure
* @is_high: Select(0) or deselect (1) the chip select line
*/
@@ -390,11 +507,27 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
u32 genfifoentry = 0x0, statusreg;
genfifoentry |= GQSPI_GENFIFO_MODE_SPI;
+
+ if (qspi->master->flags & SPI_MASTER_BOTH_CS) {
+ zynqmp_gqspi_selectslave(xqspi,
+ GQSPI_SELECT_FLASH_CS_BOTH,
+ GQSPI_SELECT_FLASH_BUS_BOTH);
+ } else if (qspi->master->flags & SPI_MASTER_U_PAGE) {
+ zynqmp_gqspi_selectslave(xqspi,
+ GQSPI_SELECT_FLASH_CS_UPPER,
+ GQSPI_SELECT_FLASH_BUS_LOWER);
+ } else {
+ zynqmp_gqspi_selectslave(xqspi,
+ GQSPI_SELECT_FLASH_CS_LOWER,
+ GQSPI_SELECT_FLASH_BUS_LOWER);
+ }
+
genfifoentry |= xqspi->genfifobus;
if (!is_high) {
genfifoentry |= xqspi->genfifocs;
genfifoentry |= GQSPI_GENFIFO_CS_SETUP;
+ xqspi->isinstr = true;
} else {
genfifoentry |= GQSPI_GENFIFO_CS_HOLD;
}
@@ -415,8 +548,7 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
if ((statusreg & GQSPI_ISR_GENFIFOEMPTY_MASK) &&
(statusreg & GQSPI_ISR_TXEMPTY_MASK))
break;
- else
- cpu_relax();
+ cpu_relax();
} while (!time_after_eq(jiffies, timeout));
if (time_after_eq(jiffies, timeout))
@@ -424,7 +556,7 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
}
/**
- * zynqmp_qspi_setup_transfer: Configure QSPI controller for specified
+ * zynqmp_qspi_setup_transfer - Configure QSPI controller for specified
* transfer
* @qspi: Pointer to the spi_device structure
* @transfer: Pointer to the spi_transfer structure which provides
@@ -457,33 +589,39 @@ static int zynqmp_qspi_setup_transfer(struct spi_device *qspi,
else
req_hz = qspi->max_speed_hz;
- /* Set the clock frequency */
- /* If req_hz == 0, default to lowest speed */
- clk_rate = clk_get_rate(xqspi->refclk);
+ if (xqspi->speed_hz != req_hz) {
+ /* Set the clock frequency */
+ /* If req_hz == 0, default to lowest speed */
+ clk_rate = clk_get_rate(xqspi->refclk);
- while ((baud_rate_val < GQSPI_BAUD_DIV_MAX) &&
- (clk_rate /
- (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) > req_hz)
- baud_rate_val++;
+ while ((baud_rate_val < GQSPI_BAUD_DIV_MAX) &&
+ (clk_rate /
+ (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) > req_hz)
+ baud_rate_val++;
- config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
+ config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
- /* Set the QSPI clock phase and clock polarity */
- config_reg &= (~GQSPI_CFG_CLK_PHA_MASK) & (~GQSPI_CFG_CLK_POL_MASK);
+ /* Set the QSPI clock phase and clock polarity */
+ config_reg &= (~GQSPI_CFG_CLK_PHA_MASK) &
+ (~GQSPI_CFG_CLK_POL_MASK);
- if (qspi->mode & SPI_CPHA)
- config_reg |= GQSPI_CFG_CLK_PHA_MASK;
- if (qspi->mode & SPI_CPOL)
- config_reg |= GQSPI_CFG_CLK_POL_MASK;
+ if (qspi->mode & SPI_CPHA)
+ config_reg |= GQSPI_CFG_CLK_PHA_MASK;
+ if (qspi->mode & SPI_CPOL)
+ config_reg |= GQSPI_CFG_CLK_POL_MASK;
+ config_reg &= ~GQSPI_CFG_BAUD_RATE_DIV_MASK;
+ config_reg |= (baud_rate_val << GQSPI_CFG_BAUD_RATE_DIV_SHIFT);
+ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ xqspi->speed_hz = clk_rate / (GQSPI_BAUD_DIV_SHIFT <<
+ baud_rate_val);
+ zynqmp_qspi_set_tapdelay(xqspi, baud_rate_val);
+ }
- config_reg &= ~GQSPI_CFG_BAUD_RATE_DIV_MASK;
- config_reg |= (baud_rate_val << GQSPI_CFG_BAUD_RATE_DIV_SHIFT);
- zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
return 0;
}
/**
- * zynqmp_qspi_setup: Configure the QSPI controller
+ * zynqmp_qspi_setup - Configure the QSPI controller
* @qspi: Pointer to the spi_device structure
*
* Sets the operational mode of QSPI controller for the next QSPI transfer,
@@ -499,7 +637,7 @@ static int zynqmp_qspi_setup(struct spi_device *qspi)
}
/**
- * zynqmp_qspi_filltxfifo: Fills the TX FIFO as long as there is room in
+ * zynqmp_qspi_filltxfifo - Fills the TX FIFO as long as there is room in
* the FIFO or the bytes required to be
* transmitted.
* @xqspi: Pointer to the zynqmp_qspi structure
@@ -525,7 +663,7 @@ static void zynqmp_qspi_filltxfifo(struct zynqmp_qspi *xqspi, int size)
}
/**
- * zynqmp_qspi_readrxfifo: Fills the RX FIFO as long as there is room in
+ * zynqmp_qspi_readrxfifo - Fills the RX FIFO as long as there is room in
* the FIFO.
* @xqspi: Pointer to the zynqmp_qspi structure
* @size: Number of bytes to be copied from RX buffer to RX FIFO
@@ -538,7 +676,7 @@ static void zynqmp_qspi_readrxfifo(struct zynqmp_qspi *xqspi, u32 size)
while ((count < size) && (xqspi->bytes_to_receive > 0)) {
if (xqspi->bytes_to_receive >= 4) {
(*(u32 *) xqspi->rxbuf) =
- zynqmp_gqspi_read(xqspi, GQSPI_RXD_OFST);
+ zynqmp_gqspi_read(xqspi, GQSPI_RXD_OFST);
xqspi->rxbuf += 4;
xqspi->bytes_to_receive -= 4;
count += 4;
@@ -553,7 +691,40 @@ static void zynqmp_qspi_readrxfifo(struct zynqmp_qspi *xqspi, u32 size)
}
/**
- * zynqmp_process_dma_irq: Handler for DMA done interrupt of QSPI
+ * zynqmp_qspi_preparedummy - Prepares the dummy entry
+ *
+ * @xqspi: Pointer to the zynqmp_qspi structure
+ * @transfer: It is a pointer to the structure containing transfer data.
+ * @genfifoentry: genfifoentry is pointer to the variable in which
+ * GENFIFO mask is returned to calling function
+ */
+static void zynqmp_qspi_preparedummy(struct zynqmp_qspi *xqspi,
+ struct spi_transfer *transfer,
+ u32 *genfifoentry)
+{
+ /* For dummy Tx and Rx are NULL */
+ *genfifoentry &= ~(GQSPI_GENFIFO_TX | GQSPI_GENFIFO_RX);
+
+ /* SPI mode */
+ *genfifoentry &= ~GQSPI_GENFIFO_MODE_QUADSPI;
+ if (xqspi->rx_bus_width == GQSPI_RX_BUS_WIDTH_QUAD ||
+ xqspi->tx_bus_width == GQSPI_TX_BUS_WIDTH_QUAD)
+ *genfifoentry |= GQSPI_GENFIFO_MODE_QUADSPI;
+ else if (xqspi->rx_bus_width == GQSPI_RX_BUS_WIDTH_DUAL ||
+ xqspi->tx_bus_width == GQSPI_TX_BUS_WIDTH_DUAL)
+ *genfifoentry |= GQSPI_GENFIFO_MODE_DUALSPI;
+ else
+ *genfifoentry |= GQSPI_GENFIFO_MODE_SPI;
+
+ /* Immediate data */
+ *genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK;
+
+ if (transfer->dummy)
+ *genfifoentry |= transfer->dummy;
+}
+
+/**
+ * zynqmp_process_dma_irq - Handler for DMA done interrupt of QSPI
* controller
* @xqspi: zynqmp_qspi instance pointer
*
@@ -601,7 +772,7 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi)
}
/**
- * zynqmp_qspi_irq: Interrupt service routine of the QSPI controller
+ * zynqmp_qspi_irq - Interrupt service routine of the QSPI controller
* @irq: IRQ number
* @dev_id: Pointer to the xqspi structure
*
@@ -639,23 +810,29 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) {
zynqmp_process_dma_irq(xqspi);
ret = IRQ_HANDLED;
- } else if (!(mask & GQSPI_IER_RXEMPTY_MASK) &&
- (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) {
+ } else if ((mask & GQSPI_IER_RXNEMPTY_MASK)) {
+ zynqmp_qspi_readrxfifo(xqspi, GQSPI_RX_FIFO_FILL);
+ ret = IRQ_HANDLED;
+ }
+ if (!(mask & GQSPI_IER_RXEMPTY_MASK) &&
+ (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) {
zynqmp_qspi_readrxfifo(xqspi, GQSPI_RX_FIFO_FILL);
ret = IRQ_HANDLED;
}
if ((xqspi->bytes_to_receive == 0) && (xqspi->bytes_to_transfer == 0)
&& ((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) {
- zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK);
+ zynqmp_disable_intr(xqspi);
+ xqspi->isinstr = false;
spi_finalize_current_transfer(master);
ret = IRQ_HANDLED;
}
+
return ret;
}
/**
- * zynqmp_qspi_selectspimode: Selects SPI mode - x1 or x2 or x4.
+ * zynqmp_qspi_selectspimode - Selects SPI mode - x1 or x2 or x4.
* @xqspi: xqspi is a pointer to the GQSPI instance
* @spimode: spimode - SPI or DUAL or QUAD.
* Return: Mask to set desired SPI mode in GENFIFO entry.
@@ -683,7 +860,7 @@ static inline u32 zynqmp_qspi_selectspimode(struct zynqmp_qspi *xqspi,
}
/**
- * zynq_qspi_setuprxdma: This function sets up the RX DMA operation
+ * zynq_qspi_setuprxdma - This function sets up the RX DMA operation
* @xqspi: xqspi is a pointer to the GQSPI instance.
*/
static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
@@ -692,8 +869,9 @@ static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
dma_addr_t addr;
u64 dma_align = (u64)(uintptr_t)xqspi->rxbuf;
- if ((xqspi->bytes_to_receive < 8) ||
- ((dma_align & GQSPI_DMA_UNALIGN) != 0x0)) {
+ if (((xqspi->bytes_to_receive < 8) || (xqspi->io_mode)) ||
+ ((dma_align & GQSPI_DMA_UNALIGN) != 0x0) ||
+ is_vmalloc_addr(xqspi->rxbuf)) {
/* Setting to IO mode */
config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
@@ -708,8 +886,10 @@ static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
addr = dma_map_single(xqspi->dev, (void *)xqspi->rxbuf,
rx_bytes, DMA_FROM_DEVICE);
- if (dma_mapping_error(xqspi->dev, addr))
+ if (dma_mapping_error(xqspi->dev, addr)) {
dev_err(xqspi->dev, "ERR:rxdma:memory not mapped\n");
+ return;
+ }
xqspi->dma_rx_bytes = rx_bytes;
xqspi->dma_addr = addr;
@@ -733,7 +913,7 @@ static void zynq_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
}
/**
- * zynqmp_qspi_txrxsetup: This function checks the TX/RX buffers in
+ * zynqmp_qspi_txrxsetup - This function checks the TX/RX buffers in
* the transfer and sets up the GENFIFO entries,
* TX FIFO as required.
* @xqspi: xqspi is a pointer to the GQSPI instance.
@@ -755,7 +935,7 @@ static void zynqmp_qspi_txrxsetup(struct zynqmp_qspi *xqspi,
*genfifoentry |= GQSPI_GENFIFO_TX;
*genfifoentry |=
zynqmp_qspi_selectspimode(xqspi, transfer->tx_nbits);
- xqspi->bytes_to_transfer = transfer->len;
+ xqspi->bytes_to_transfer = transfer->len - (transfer->dummy/8);
if (xqspi->mode == GQSPI_MODE_DMA) {
config_reg = zynqmp_gqspi_read(xqspi,
GQSPI_CONFIG_OFST);
@@ -784,7 +964,7 @@ static void zynqmp_qspi_txrxsetup(struct zynqmp_qspi *xqspi,
}
/**
- * zynqmp_qspi_start_transfer: Initiates the QSPI transfer
+ * zynqmp_qspi_start_transfer - Initiates the QSPI transfer
* @master: Pointer to the spi_master structure which provides
* information about the controller.
* @qspi: Pointer to the spi_device structure
@@ -811,18 +991,28 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
genfifoentry |= xqspi->genfifocs;
genfifoentry |= xqspi->genfifobus;
+ if (!xqspi->isinstr && (master->flags & SPI_MASTER_DATA_STRIPE)) {
+ if (transfer->stripe)
+ genfifoentry |= GQSPI_GENFIFO_STRIPE;
+ }
zynqmp_qspi_txrxsetup(xqspi, transfer, &genfifoentry);
if (xqspi->mode == GQSPI_MODE_DMA)
transfer_len = xqspi->dma_rx_bytes;
else
- transfer_len = transfer->len;
+ transfer_len = transfer->len - (transfer->dummy/8);
xqspi->genfifoentry = genfifoentry;
if ((transfer_len) < GQSPI_GENFIFO_IMM_DATA_MASK) {
genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK;
genfifoentry |= transfer_len;
zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
+ if (transfer->dummy || transfer->tx_nbits >= 1) {
+ zynqmp_qspi_preparedummy(xqspi, transfer,
+ &genfifoentry);
+ zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST,
+ genfifoentry);
+ }
} else {
int tempcount = transfer_len;
u32 exponent = 8; /* 2^8 = 256 */
@@ -849,6 +1039,12 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
if (imm_data != 0) {
genfifoentry &= ~GQSPI_GENFIFO_EXP;
genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK;
+ if (imm_data % 4 != 0) {
+ if (((imm_data + 4 - (imm_data % 4)) & 0xFF) == 0x00)
+ imm_data = 0xFF;
+ else
+ imm_data = imm_data + 4 - (imm_data % 4);
+ }
genfifoentry |= (u8) (imm_data & 0xFF);
zynqmp_gqspi_write(xqspi,
GQSPI_GEN_FIFO_OFST, genfifoentry);
@@ -869,7 +1065,6 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
if (xqspi->txbuf != NULL)
/* Enable interrupts for TX */
zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
- GQSPI_IER_TXEMPTY_MASK |
GQSPI_IER_GENFIFOEMPTY_MASK |
GQSPI_IER_TXNOT_FULL_MASK);
@@ -883,8 +1078,7 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
} else {
zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
GQSPI_IER_GENFIFOEMPTY_MASK |
- GQSPI_IER_RXNEMPTY_MASK |
- GQSPI_IER_RXEMPTY_MASK);
+ GQSPI_IER_RXNEMPTY_MASK);
}
}
@@ -892,8 +1086,8 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
}
/**
- * zynqmp_qspi_suspend: Suspend method for the QSPI driver
- * @_dev: Address of the platform_device structure
+ * zynqmp_qspi_suspend - Suspend method for the QSPI driver
+ * @dev: Address of the platform_device structure
*
* This function stops the QSPI driver queue and disables the QSPI controller
*
@@ -911,7 +1105,7 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev)
}
/**
- * zynqmp_qspi_resume: Resume method for the QSPI driver
+ * zynqmp_qspi_resume - Resume method for the QSPI driver
* @dev: Address of the platform_device structure
*
* The function starts the QSPI driver queue and initializes the QSPI
@@ -938,10 +1132,12 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev)
return ret;
}
+ zynqmp_qspi_init_hw(xqspi);
spi_master_resume(master);
clk_disable(xqspi->refclk);
clk_disable(xqspi->pclk);
+
return 0;
}
@@ -994,14 +1190,38 @@ static int __maybe_unused zynqmp_runtime_resume(struct device *dev)
return 0;
}
+static int __maybe_unused zynqmp_runtime_idle(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct zynqmp_qspi *xqspi = spi_master_get_devdata(master);
+ u32 value;
+
+ value = zynqmp_gqspi_read(xqspi, GQSPI_EN_OFST);
+ if (value)
+ return -EBUSY;
+
+ return 0;
+}
+
static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = {
SET_RUNTIME_PM_OPS(zynqmp_runtime_suspend,
- zynqmp_runtime_resume, NULL)
+ zynqmp_runtime_resume, zynqmp_runtime_idle)
SET_SYSTEM_SLEEP_PM_OPS(zynqmp_qspi_suspend, zynqmp_qspi_resume)
};
+static const struct qspi_platform_data versal_qspi_def = {
+ .quirks = QSPI_QUIRK_HAS_TAPDELAY,
+};
+
+static const struct of_device_id zynqmp_qspi_of_match[] = {
+ { .compatible = "xlnx,zynqmp-qspi-1.0"},
+ { .compatible = "xlnx,versal-qspi-1.0", .data = &versal_qspi_def },
+ { /* End of table */ }
+};
+
/**
- * zynqmp_qspi_probe: Probe method for the QSPI driver
+ * zynqmp_qspi_probe - Probe method for the QSPI driver
* @pdev: Pointer to the platform_device structure
*
* This function initializes the driver data structures and the hardware.
@@ -1015,6 +1235,11 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
struct zynqmp_qspi *xqspi;
struct resource *res;
struct device *dev = &pdev->dev;
+ struct device_node *nc;
+ const struct of_device_id *match;
+ u32 num_cs;
+ u32 rx_bus_width;
+ u32 tx_bus_width;
eemi_ops = zynqmp_pm_get_eemi_ops();
if (IS_ERR(eemi_ops))
@@ -1028,6 +1253,14 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, master);
+ match = of_match_node(zynqmp_qspi_of_match, pdev->dev.of_node);
+ if (match) {
+ const struct qspi_platform_data *p_data = match->data;
+
+ if (p_data && (p_data->quirks & QSPI_QUIRK_HAS_TAPDELAY))
+ xqspi->has_tapdelay = true;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xqspi->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xqspi->regs)) {
@@ -1066,11 +1299,16 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+
+ if (of_property_read_bool(pdev->dev.of_node, "has-io-mode"))
+ xqspi->io_mode = true;
+
/* QSPI controller initializations */
zynqmp_qspi_init_hw(xqspi);
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
+
xqspi->irq = platform_get_irq(pdev, 0);
if (xqspi->irq <= 0) {
ret = -ENXIO;
@@ -1085,8 +1323,37 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
goto clk_dis_all;
}
- master->num_chipselect = GQSPI_DEFAULT_NUM_CS;
+ xqspi->rx_bus_width = GQSPI_RX_BUS_WIDTH_SINGLE;
+ for_each_available_child_of_node(pdev->dev.of_node, nc) {
+ ret = of_property_read_u32(nc, "spi-rx-bus-width",
+ &rx_bus_width);
+ if (!ret) {
+ xqspi->rx_bus_width = rx_bus_width;
+ break;
+ }
+ }
+ if (ret)
+ dev_err(dev, "rx bus width not found\n");
+
+ xqspi->tx_bus_width = GQSPI_TX_BUS_WIDTH_SINGLE;
+ for_each_available_child_of_node(pdev->dev.of_node, nc) {
+ ret = of_property_read_u32(nc, "spi-tx-bus-width",
+ &tx_bus_width);
+ if (!ret) {
+ xqspi->tx_bus_width = tx_bus_width;
+ break;
+ }
+ }
+ if (ret)
+ dev_err(dev, "tx bus width not found\n");
+
+ ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
+ if (ret < 0)
+ master->num_chipselect = GQSPI_DEFAULT_NUM_CS;
+ else
+ master->num_chipselect = num_cs;
+ dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
master->setup = zynqmp_qspi_setup;
master->set_cs = zynqmp_qspi_chipselect;
master->transfer_one = zynqmp_qspi_start_transfer;
@@ -1097,6 +1364,8 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
+ xqspi->speed_hz = master->max_speed_hz;
+ master->auto_runtime_pm = true;
if (master->dev.parent == NULL)
master->dev.parent = &master->dev;
@@ -1120,7 +1389,7 @@ remove_master:
}
/**
- * zynqmp_qspi_remove: Remove method for the QSPI driver
+ * zynqmp_qspi_remove - Remove method for the QSPI driver
* @pdev: Pointer to the platform_device structure
*
* This function is called if a device is physically removed from the system or
@@ -1145,11 +1414,6 @@ static int zynqmp_qspi_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id zynqmp_qspi_of_match[] = {
- { .compatible = "xlnx,zynqmp-qspi-1.0", },
- { /* End of table */ }
-};
-
MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match);
static struct platform_driver zynqmp_qspi_driver = {
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index be5b4b65c016..bb2bb9bfe4fe 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3056,6 +3056,14 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
}
}
+ /*
+ * Data stripe option is selected if and only if when
+ * two chips are enabled
+ */
+ if ((ctlr->flags & SPI_MASTER_DATA_STRIPE)
+ && !(ctlr->flags & SPI_MASTER_BOTH_CS))
+ return -EINVAL;
+
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by