Zynq qspi controller driver supports single bus
with singe chipselect.
Zynq qspi can be operated in below connection modes
- single qspi
- dual qspi, with dual stacked
- dual qspi, with dual parallel
Signed-off-by: Jagannadha Sutradharudu Teki <[email protected]>
---
arch/arm/include/asm/arch-zynq/hardware.h | 1 +
drivers/spi/Makefile | 1 +
drivers/spi/zynq_qspi.c | 447 ++++++++++++++++++++++++++++++
3 files changed, 449 insertions(+)
create mode 100644 drivers/spi/zynq_qspi.c
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h
b/arch/arm/include/asm/arch-zynq/hardware.h
index cd69677..05870ae 100644
--- a/arch/arm/include/asm/arch-zynq/hardware.h
+++ b/arch/arm/include/asm/arch-zynq/hardware.h
@@ -19,6 +19,7 @@
#define ZYNQ_I2C_BASEADDR1 0xE0005000
#define ZYNQ_SPI_BASEADDR0 0xE0006000
#define ZYNQ_SPI_BASEADDR1 0xE0007000
+#define ZYNQ_QSPI_BASEADDR 0xE000D000
#define ZYNQ_DDRC_BASEADDR 0xF8006000
/* Reflect slcr offsets */
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 27902fe..5fafee0 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -37,3 +37,4 @@ obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
obj-$(CONFIG_TI_QSPI) += ti_qspi.o
obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
+obj-$(CONFIG_ZYNQ_QSPI) += zynq_qspi.o
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
new file mode 100644
index 0000000..f38ebca
--- /dev/null
+++ b/drivers/spi/zynq_qspi.c
@@ -0,0 +1,447 @@
+/*
+ * (C) Copyright 2013 Xilinx, Inc.
+ *
+ * Zynq PS Quad-SPI(QSPI) controller driver (master mode only)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+
+/* zynq spi register bit masks ZYNQ_QSPI_<REG>_<BIT>_MASK */
+#define ZYNQ_QSPI_CR_IFMODE_MASK (1 << 31) /* Flash intrface mode*/
+#define ZYNQ_QSPI_CR_MSA_MASK (1 << 15) /* Manual start enb */
+#define ZYNQ_QSPI_CR_MCS_MASK (1 << 14) /* Manual chip select */
+#define ZYNQ_QSPI_CR_PCS_MASK (1 << 10) /* Peri chip select */
+#define ZYNQ_QSPI_CR_FW_MASK (0x3 << 6) /* FIFO width */
+#define ZYNQ_QSPI_CR_BRD_MASK (0x7 << 3) /* Baud rate div */
+#define ZYNQ_QSPI_CR_CPHA_MASK (1 << 2) /* Clock phase */
+#define ZYNQ_QSPI_CR_CPOL_MASK (1 << 1) /* Clock polarity */
+#define ZYNQ_QSPI_CR_MSTREN_MASK (1 << 0) /* Mode select */
+#define ZYNQ_QSPI_IXR_RXNEMPTY_MASK (1 << 4) /* RX_FIFO_not_empty */
+#define ZYNQ_QSPI_IXR_TXOW_MASK (1 << 2) /* TX_FIFO_not_full */
+#define ZYNQ_QSPI_IXR_ALL_MASK 0x7F /* All IXR bits */
+#define ZYNQ_QSPI_ENR_SPI_EN_MASK (1 << 0) /* SPI Enable */
+
+/* QSPI Transmit Data Register */
+#define ZYNQ_QSPI_TXD_00_00_OFFSET 0x1C /* Transmit 4-byte inst */
+#define ZYNQ_QSPI_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst */
+#define ZYNQ_QSPI_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst */
+#define ZYNQ_QSPI_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst */
+
+/* Definitions of the flash commands - Flash insts in ascending order */
+#define ZYNQ_QSPI_FLASH_INST_WRSR 0x01 /* Write status register */
+#define ZYNQ_QSPI_FLASH_INST_PP 0x02 /* Page program */
+#define ZYNQ_QSPI_FLASH_INST_WRDS 0x04 /* Write disable */
+#define ZYNQ_QSPI_FLASH_INST_RDSR1 0x05 /* Read status register 1 */
+#define ZYNQ_QSPI_FLASH_INST_WREN 0x06 /* Write enable */
+#define ZYNQ_QSPI_FLASH_INST_AFR 0x0B /* Fast read data bytes */
+#define ZYNQ_QSPI_FLASH_INST_BE_4K 0x20 /* Erase 4KiB block */
+#define ZYNQ_QSPI_FLASH_INST_RDSR2 0x35 /* Read status register 2 */
+#define ZYNQ_QSPI_FLASH_INST_BE_32K 0x52 /* Erase 32KiB block */
+#define ZYNQ_QSPI_FLASH_INST_RDID 0x9F /* Read JEDEC ID */
+#define ZYNQ_QSPI_FLASH_INST_SE 0xD8 /* Sector erase
(usually 64KB)*/
+
+#define ZYNQ_QSPI_FIFO_DEPTH 63
+#ifndef CONFIG_SYS_ZYNQ_QSPI_WAIT
+#define CONFIG_SYS_ZYNQ_QSPI_WAIT CONFIG_SYS_HZ/100 /* 10 ms */
+#endif
+
+/* zynq qspi register set */
+struct zynq_qspi_regs {
+ u32 cr; /* 0x00 */
+ u32 isr; /* 0x04 */
+ u32 ier; /* 0x08 */
+ u32 idr; /* 0x0C */
+ u32 imr; /* 0x10 */
+ u32 enr; /* 0x14 */
+ u32 dr; /* 0x18 */
+ u32 txd0r; /* 0x1C */
+ u32 rxdr; /* 0x20 */
+ u32 sicr; /* 0x24 */
+ u32 txftr; /* 0x28 */
+ u32 rxftr; /* 0x2C */
+ u32 gpior; /* 0x30 */
+ u32 reserved0[19];
+ u32 txd1r; /* 0x80 */
+ u32 txd2r; /* 0x84 */
+ u32 txd3r; /* 0x88 */
+};
+
+/*
+ * struct zynq_qspi_inst_format - Defines qspi flash instruction format
+ * @inst: Instruction code
+ * @inst_size: Size of the instruction including address bytes
+ * @inst_off: Register address where instruction has to be written
+ */
+struct zynq_qspi_inst_format {
+ u8 inst;
+ u8 inst_size;
+ u8 inst_off;
+};
+
+/* List of all the QSPI instructions and its format */
+static struct zynq_qspi_inst_format flash_inst[] = {
+ {ZYNQ_QSPI_FLASH_INST_WRSR, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_PP, 4, ZYNQ_QSPI_TXD_00_00_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_WRDS, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_RDSR1, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_WREN, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_AFR, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_BE_4K, 4, ZYNQ_QSPI_TXD_00_00_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_RDSR2, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_BE_32K, 4, ZYNQ_QSPI_TXD_00_00_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_RDID, 1, ZYNQ_QSPI_TXD_00_01_OFFSET},
+ {ZYNQ_QSPI_FLASH_INST_SE, 4, ZYNQ_QSPI_TXD_00_00_OFFSET},
+ /* Add all the instructions supported by the flash device */
+};
+
+/* zynq spi slave */
+struct zynq_qspi_slave {
+ struct spi_slave slave;
+ struct zynq_qspi_regs *base;
+ u8 mode;
+ u8 is_inst;
+ u8 fifo_depth;
+ const void *tx_buf;
+ void *rx_buf;
+ u32 tx_len;
+ u32 rx_len;
+ u32 speed_hz;
+ u32 input_hz;
+ u32 req_hz;
+};
+
+static inline struct zynq_qspi_slave *to_zynq_qspi_slave(
+ struct spi_slave *slave)
+{
+ return container_of(slave, struct zynq_qspi_slave, slave);
+}
+
+static void zynq_qspi_init_hw(struct zynq_qspi_slave *zslave)
+{
+ u32 confr;
+
+ /* Disable SPI */
+ writel(~ZYNQ_QSPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+
+ /* Disable Interrupts */
+ writel(ZYNQ_QSPI_IXR_ALL_MASK, &zslave->base->idr);
+
+ /* Clear RX FIFO */
+ while (readl(&zslave->base->isr) &
+ ZYNQ_QSPI_IXR_RXNEMPTY_MASK)
+ readl(&zslave->base->rxdr);
+
+ /* Clear Interrupts */
+ writel(ZYNQ_QSPI_IXR_ALL_MASK, &zslave->base->isr);
+
+ /* Manual slave select and Auto start */
+ confr = ZYNQ_QSPI_CR_IFMODE_MASK | ZYNQ_QSPI_CR_MCS_MASK |
+ ZYNQ_QSPI_CR_PCS_MASK | ZYNQ_QSPI_CR_FW_MASK |
+ ZYNQ_QSPI_CR_MSTREN_MASK;
+ confr &= ~ZYNQ_QSPI_CR_MSA_MASK;
+ confr &= ~ZYNQ_QSPI_CR_MSA_MASK;