Commit 1d0933eaf976ba4f3ca00356f7124b1d12ddf168

Authored by Matt Porter
Committed by Jagannadha Sutradharudu Teki
1 parent 004f15b600

spi: add TI QSPI driver

Adds a SPI master driver for the TI QSPI peripheral.
- Added quad read support.
- Added memory mapped support.

Signed-off-by: Matt Porter <matt.porter@linaro.org>
Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>

Showing 2 changed files with 312 additions and 0 deletions Side-by-side Diff

drivers/spi/Makefile
... ... @@ -38,6 +38,7 @@
38 38 COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
39 39 COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
40 40 COBJS-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
  41 +COBJS-$(CONFIG_TI_QSPI) += ti_qspi.o
41 42 COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o
42 43 COBJS-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
43 44  
drivers/spi/ti_qspi.c
  1 +/*
  2 + * TI QSPI driver
  3 + *
  4 + * Copyright (C) 2013, Texas Instruments, Incorporated
  5 + *
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + */
  8 +
  9 +#include <common.h>
  10 +#include <asm/io.h>
  11 +#include <asm/arch/omap.h>
  12 +#include <malloc.h>
  13 +#include <spi.h>
  14 +
  15 +/* ti qpsi register bit masks */
  16 +#define QSPI_TIMEOUT 2000000
  17 +#define QSPI_FCLK 192000000
  18 +/* clock control */
  19 +#define QSPI_CLK_EN (1 << 31)
  20 +#define QSPI_CLK_DIV_MAX 0xffff
  21 +/* command */
  22 +#define QSPI_EN_CS(n) (n << 28)
  23 +#define QSPI_WLEN(n) ((n-1) << 19)
  24 +#define QSPI_3_PIN (1 << 18)
  25 +#define QSPI_RD_SNGL (1 << 16)
  26 +#define QSPI_WR_SNGL (2 << 16)
  27 +#define QSPI_INVAL (4 << 16)
  28 +#define QSPI_RD_QUAD (7 << 16)
  29 +/* device control */
  30 +#define QSPI_DD(m, n) (m << (3 + n*8))
  31 +#define QSPI_CKPHA(n) (1 << (2 + n*8))
  32 +#define QSPI_CSPOL(n) (1 << (1 + n*8))
  33 +#define QSPI_CKPOL(n) (1 << (n*8))
  34 +/* status */
  35 +#define QSPI_WC (1 << 1)
  36 +#define QSPI_BUSY (1 << 0)
  37 +#define QSPI_WC_BUSY (QSPI_WC | QSPI_BUSY)
  38 +#define QSPI_XFER_DONE QSPI_WC
  39 +#define MM_SWITCH 0x01
  40 +#define MEM_CS 0x100
  41 +#define MEM_CS_UNSELECT 0xfffff0ff
  42 +#define MMAP_START_ADDR 0x5c000000
  43 +#define CORE_CTRL_IO 0x4a002558
  44 +
  45 +#define QSPI_CMD_READ (0x3 << 0)
  46 +#define QSPI_CMD_READ_QUAD (0x6b << 0)
  47 +#define QSPI_CMD_READ_FAST (0x0b << 0)
  48 +#define QSPI_SETUP0_NUM_A_BYTES (0x2 << 8)
  49 +#define QSPI_SETUP0_NUM_D_BYTES_NO_BITS (0x0 << 10)
  50 +#define QSPI_SETUP0_NUM_D_BYTES_8_BITS (0x1 << 10)
  51 +#define QSPI_SETUP0_READ_NORMAL (0x0 << 12)
  52 +#define QSPI_SETUP0_READ_QUAD (0x3 << 12)
  53 +#define QSPI_CMD_WRITE (0x2 << 16)
  54 +#define QSPI_NUM_DUMMY_BITS (0x0 << 24)
  55 +
  56 +/* ti qspi register set */
  57 +struct ti_qspi_regs {
  58 + u32 pid;
  59 + u32 pad0[3];
  60 + u32 sysconfig;
  61 + u32 pad1[3];
  62 + u32 int_stat_raw;
  63 + u32 int_stat_en;
  64 + u32 int_en_set;
  65 + u32 int_en_ctlr;
  66 + u32 intc_eoi;
  67 + u32 pad2[3];
  68 + u32 clk_ctrl;
  69 + u32 dc;
  70 + u32 cmd;
  71 + u32 status;
  72 + u32 data;
  73 + u32 setup0;
  74 + u32 setup1;
  75 + u32 setup2;
  76 + u32 setup3;
  77 + u32 memswitch;
  78 + u32 data1;
  79 + u32 data2;
  80 + u32 data3;
  81 +};
  82 +
  83 +/* ti qspi slave */
  84 +struct ti_qspi_slave {
  85 + struct spi_slave slave;
  86 + struct ti_qspi_regs *base;
  87 + unsigned int mode;
  88 + u32 cmd;
  89 + u32 dc;
  90 +};
  91 +
  92 +static inline struct ti_qspi_slave *to_ti_qspi_slave(struct spi_slave *slave)
  93 +{
  94 + return container_of(slave, struct ti_qspi_slave, slave);
  95 +}
  96 +
  97 +static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave)
  98 +{
  99 + struct spi_slave *slave = &qslave->slave;
  100 + u32 memval = 0;
  101 +
  102 + slave->memory_map = (void *)MMAP_START_ADDR;
  103 +
  104 + memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES |
  105 + QSPI_SETUP0_NUM_D_BYTES_NO_BITS |
  106 + QSPI_SETUP0_READ_NORMAL | QSPI_CMD_WRITE |
  107 + QSPI_NUM_DUMMY_BITS;
  108 +
  109 + writel(memval, &qslave->base->setup0);
  110 +}
  111 +
  112 +static void ti_spi_set_speed(struct spi_slave *slave, uint hz)
  113 +{
  114 + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
  115 + uint clk_div;
  116 +
  117 + debug("ti_spi_set_speed: hz: %d, clock divider %d\n", hz, clk_div);
  118 +
  119 + if (!hz)
  120 + clk_div = 0;
  121 + else
  122 + clk_div = (QSPI_FCLK / hz) - 1;
  123 +
  124 + /* disable SCLK */
  125 + writel(readl(&qslave->base->clk_ctrl) & ~QSPI_CLK_EN,
  126 + &qslave->base->clk_ctrl);
  127 +
  128 + /* assign clk_div values */
  129 + if (clk_div < 0)
  130 + clk_div = 0;
  131 + else if (clk_div > QSPI_CLK_DIV_MAX)
  132 + clk_div = QSPI_CLK_DIV_MAX;
  133 +
  134 + /* enable SCLK */
  135 + writel(QSPI_CLK_EN | clk_div, &qslave->base->clk_ctrl);
  136 +}
  137 +
  138 +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
  139 +{
  140 + return 1;
  141 +}
  142 +
  143 +void spi_cs_activate(struct spi_slave *slave)
  144 +{
  145 + /* CS handled in xfer */
  146 + return;
  147 +}
  148 +
  149 +void spi_cs_deactivate(struct spi_slave *slave)
  150 +{
  151 + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
  152 +
  153 + debug("spi_cs_deactivate: 0x%08x\n", (u32)slave);
  154 +
  155 + writel(qslave->cmd | QSPI_INVAL, &qslave->base->cmd);
  156 +}
  157 +
  158 +void spi_init(void)
  159 +{
  160 + /* nothing to do */
  161 +}
  162 +
  163 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  164 + unsigned int max_hz, unsigned int mode)
  165 +{
  166 + struct ti_qspi_slave *qslave;
  167 +
  168 + qslave = spi_alloc_slave(struct ti_qspi_slave, bus, cs);
  169 + if (!qslave) {
  170 + printf("SPI_error: Fail to allocate ti_qspi_slave\n");
  171 + return NULL;
  172 + }
  173 +
  174 + qslave->base = (struct ti_qspi_regs *)QSPI_BASE;
  175 + qslave->mode = mode;
  176 +
  177 + ti_spi_set_speed(&qslave->slave, max_hz);
  178 +
  179 +#ifdef CONFIG_TI_SPI_MMAP
  180 + ti_spi_setup_spi_register(qslave);
  181 +#endif
  182 +
  183 + return &qslave->slave;
  184 +}
  185 +
  186 +void spi_free_slave(struct spi_slave *slave)
  187 +{
  188 + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
  189 + free(qslave);
  190 +}
  191 +
  192 +int spi_claim_bus(struct spi_slave *slave)
  193 +{
  194 + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
  195 +
  196 + debug("spi_claim_bus: bus:%i cs:%i\n", slave->bus, slave->cs);
  197 +
  198 + qslave->dc = 0;
  199 + if (qslave->mode & SPI_CPHA)
  200 + qslave->dc |= QSPI_CKPHA(slave->cs);
  201 + if (qslave->mode & SPI_CPOL)
  202 + qslave->dc |= QSPI_CKPOL(slave->cs);
  203 + if (qslave->mode & SPI_CS_HIGH)
  204 + qslave->dc |= QSPI_CSPOL(slave->cs);
  205 +
  206 + writel(qslave->dc, &qslave->base->dc);
  207 + writel(0, &qslave->base->cmd);
  208 + writel(0, &qslave->base->data);
  209 +
  210 + return 0;
  211 +}
  212 +
  213 +void spi_release_bus(struct spi_slave *slave)
  214 +{
  215 + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
  216 +
  217 + debug("spi_release_bus: bus:%i cs:%i\n", slave->bus, slave->cs);
  218 +
  219 + writel(0, &qslave->base->dc);
  220 + writel(0, &qslave->base->cmd);
  221 + writel(0, &qslave->base->data);
  222 +}
  223 +
  224 +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
  225 + void *din, unsigned long flags)
  226 +{
  227 + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave);
  228 + uint words = bitlen >> 3; /* fixed 8-bit word length */
  229 + const uchar *txp = dout;
  230 + uchar *rxp = din;
  231 + uint status;
  232 + int timeout, val;
  233 +
  234 + debug("spi_xfer: bus:%i cs:%i bitlen:%i words:%i flags:%lx\n",
  235 + slave->bus, slave->cs, bitlen, words, flags);
  236 +
  237 + /* Setup mmap flags */
  238 + if (flags & SPI_XFER_MMAP) {
  239 + writel(MM_SWITCH, &qslave->base->memswitch);
  240 + val = readl(CORE_CTRL_IO);
  241 + val |= MEM_CS;
  242 + writel(val, CORE_CTRL_IO);
  243 + return 0;
  244 + } else if (flags & SPI_XFER_MMAP_END) {
  245 + writel(~MM_SWITCH, &qslave->base->memswitch);
  246 + val = readl(CORE_CTRL_IO);
  247 + val &= MEM_CS_UNSELECT;
  248 + writel(val, CORE_CTRL_IO);
  249 + return 0;
  250 + }
  251 +
  252 + if (bitlen == 0)
  253 + return -1;
  254 +
  255 + if (bitlen % 8) {
  256 + debug("spi_xfer: Non byte aligned SPI transfer\n");
  257 + return -1;
  258 + }
  259 +
  260 + /* Setup command reg */
  261 + qslave->cmd = 0;
  262 + qslave->cmd |= QSPI_WLEN(8);
  263 + qslave->cmd |= QSPI_EN_CS(slave->cs);
  264 + if (flags & SPI_3WIRE)
  265 + qslave->cmd |= QSPI_3_PIN;
  266 + qslave->cmd |= 0xfff;
  267 +
  268 + while (words--) {
  269 + if (txp) {
  270 + debug("tx cmd %08x dc %08x data %02x\n",
  271 + qslave->cmd | QSPI_WR_SNGL, qslave->dc, *txp);
  272 + writel(*txp++, &qslave->base->data);
  273 + writel(qslave->cmd | QSPI_WR_SNGL,
  274 + &qslave->base->cmd);
  275 + status = readl(&qslave->base->status);
  276 + timeout = QSPI_TIMEOUT;
  277 + while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
  278 + if (--timeout < 0) {
  279 + printf("spi_xfer: TX timeout!\n");
  280 + return -1;
  281 + }
  282 + status = readl(&qslave->base->status);
  283 + }
  284 + debug("tx done, status %08x\n", status);
  285 + }
  286 + if (rxp) {
  287 + qslave->cmd |= QSPI_RD_SNGL;
  288 + debug("rx cmd %08x dc %08x\n",
  289 + qslave->cmd, qslave->dc);
  290 + writel(qslave->cmd, &qslave->base->cmd);
  291 + status = readl(&qslave->base->status);
  292 + timeout = QSPI_TIMEOUT;
  293 + while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
  294 + if (--timeout < 0) {
  295 + printf("spi_xfer: RX timeout!\n");
  296 + return -1;
  297 + }
  298 + status = readl(&qslave->base->status);
  299 + }
  300 + *rxp++ = readl(&qslave->base->data);
  301 + debug("rx done, status %08x, read %02x\n",
  302 + status, *(rxp-1));
  303 + }
  304 + }
  305 +
  306 + /* Terminate frame */
  307 + if (flags & SPI_XFER_END)
  308 + spi_cs_deactivate(slave);
  309 +
  310 + return 0;
  311 +}