1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <stdio.h>
14#include <stdbool.h>
15#include <platsupport/spi.h>
16#include <utils/zf_log.h>
17
18#define SPI_PAGE_PADDR 0x7000D000
19
20#define SPI0_PADDR 0x7000D400
21#define SPI1_PADDR 0x7000D600
22#define SPI2_PADDR 0x7000D800
23#define SPI3_PADDR 0x7000DA00
24#define SPI4_PADDR 0x7000DC00
25#define SPI5_PADDR 0x7000DE00
26
27#define SPI0_OFFSET (SPI0_PADDR - SPI_PAGE_PADDR)
28
29/* COMMAND1 */
30#define SPI_CMD1_GO                     (BIT(31))
31#define SPI_CMD1_M_S                    (BIT(30))
32#define SPI_CMD1_MODE_MASK              0x3
33#define SPI_CMD1_MODE_SHIFT             28
34#define SPI_CMD1_CS_SEL_MASK            0x3
35#define SPI_CMD1_CS_SEL_SHIFT           26
36#define SPI_CMD1_CS_POL_INACTIVE3       (BIT(25))
37#define SPI_CMD1_CS_POL_INACTIVE2       (BIT(24))
38#define SPI_CMD1_CS_POL_INACTIVE1       (BIT(23))
39#define SPI_CMD1_CS_POL_INACTIVE0       (BIT(22))
40#define SPI_CMD1_CS_SW_HW               (BIT(21))
41#define SPI_CMD1_CS_SW_VAL              (BIT(20))
42#define SPI_CMD1_IDLE_SDA_MASK          0x3
43#define SPI_CMD1_IDLE_SDA_SHIFT         18
44#define SPI_CMD1_BIDIR                  (BIT(17))
45#define SPI_CMD1_LSBI_FE                (BIT(16))
46#define SPI_CMD1_LSBY_FE                (BIT(15))
47#define SPI_CMD1_BOTH_EN_BIT            (BIT(14))
48#define SPI_CMD1_BOTH_EN_BYTE           (BIT(13))
49#define SPI_CMD1_RX_EN                  (BIT(12))
50#define SPI_CMD1_TX_EN                  (BIT(11))
51#define SPI_CMD1_PACKED                 (BIT(5))
52#define SPI_CMD1_BIT_LEN_MASK           0x1F
53#define SPI_CMD1_BIT_LEN_SHIFT          0
54
55/* COMMAND2 */
56#define SPI_CMD2_TX_CLK_TAP_DELAY       (BIT(6))
57#define SPI_CMD2_TX_CLK_TAP_DELAY_MASK  (0x3F << 6)
58#define SPI_CMD2_RX_CLK_TAP_DELAY       (BIT(0))
59#define SPI_CMD2_RX_CLK_TAP_DELAY_MASK  (0x3F << 0)
60
61/* TRANSFER STATUS */
62#define SPI_XFER_STS_RDY                (BIT(30))
63
64/* FIFO STATUS */
65#define SPI_FIFO_STS_CS_INACTIVE        (BIT(31))
66#define SPI_FIFO_STS_FRAME_END          (BIT(30))
67#define SPI_FIFO_STS_RX_FIFO_FLUSH      (BIT(15))
68#define SPI_FIFO_STS_TX_FIFO_FLUSH      (BIT(14))
69#define SPI_FIFO_STS_ERR                (BIT(8))
70#define SPI_FIFO_STS_TX_FIFO_OVF        (BIT(7))
71#define SPI_FIFO_STS_TX_FIFO_UNR        (BIT(6))
72#define SPI_FIFO_STS_RX_FIFO_OVF        (BIT(5))
73#define SPI_FIFO_STS_RX_FIFO_UNR        (BIT(4))
74#define SPI_FIFO_STS_TX_FIFO_FULL       (BIT(3))
75#define SPI_FIFO_STS_TX_FIFO_EMPTY      (BIT(2))
76#define SPI_FIFO_STS_RX_FIFO_FULL       (BIT(1))
77#define SPI_FIFO_STS_RX_FIFO_EMPTY      (BIT(0))
78
79/* SPI CS Timing */
80#define CS_SETUP_TIME_0_SHIFT           4
81#define CS_HOLD_TIME_0_SHIFT            0
82
83/* DMA CTL */
84#define SPI_IE_RX                       (BIT(29))
85#define SPI_IE_TX                       (BIT(28))
86
87#define CLK_TAP_DELAY                   0x1f
88#define CS_SETUP_TIME                   0xf
89#define CS_HOLD_TIME                    0xf
90
91#define FIFO_SIZE                       64
92
93struct spi_regs {
94    volatile uint32_t command1;       /* 000:SPI_COMMAND1 register */
95    volatile uint32_t command2;       /* 004:SPI_COMMAND2 register */
96    volatile uint32_t timing1;        /* 008:SPI_CS_TIM1 register */
97    volatile uint32_t timing2;        /* 00c:SPI_CS_TIM2 register */
98    volatile uint32_t xfer_status;    /* 010:SPI_TRANS_STATUS register */
99    volatile uint32_t fifo_status;    /* 014:SPI_FIFO_STATUS register */
100    volatile uint32_t tx_data;        /* 018:SPI_TX_DATA register */
101    volatile uint32_t rx_data;        /* 01c:SPI_RX_DATA register */
102    volatile uint32_t dma_ctl;        /* 020:SPI_DMA_CTL register */
103    volatile uint32_t dma_blk;        /* 024:SPI_DMA_BLK register */
104    PAD_STRUCT_BETWEEN(0x24, 0x108, uint32_t);
105    volatile uint32_t tx_fifo;        /* 108:SPI_FIFO1 register */
106    PAD_STRUCT_BETWEEN(0x108, 0x188, uint32_t);
107    volatile uint32_t rx_fifo;        /* 188:SPI_FIFO2 register */
108    volatile uint32_t spare_ctl;      /* 18c:SPI_SPARE_CTRL register */
109};
110
111struct spi_bus {
112    volatile struct spi_regs* regs;
113    uint32_t clock_mode;           // see table 147 on page 2436 of the TRM
114    bool in_progress;
115    uint8_t *txbuf;
116    uint8_t *rxbuf;
117    size_t txsize, rxsize;
118    spi_chipselect_fn cs;
119    spi_callback_fn cb;
120    void* token;
121    spi_slave_config_t *curr_slave;
122};
123
124uint32_t spi_controller_offsets[] = {
125    [SPI0] = SPI0_OFFSET
126};
127
128static spi_bus_t _spi[] = {
129    [SPI0] = { .regs = NULL, .clock_mode = 0 },
130};
131
132int
133tegra_spi_init(enum spi_id id, volatile void* base, spi_chipselect_fn cs_func,
134               mux_sys_t* mux_sys, clock_sys_t* clock_sys,
135               spi_bus_t** ret_spi_bus)
136{
137    spi_bus_t* spi_bus = &_spi[id];
138    spi_bus->cs = cs_func;
139    spi_bus->regs = base + spi_controller_offsets[id];
140
141    // Clear relevant bits in fifo status register
142    uint32_t fifo_status = SPI_FIFO_STS_RX_FIFO_FLUSH |
143                  SPI_FIFO_STS_TX_FIFO_FLUSH |
144                  SPI_FIFO_STS_ERR           |
145                  SPI_FIFO_STS_TX_FIFO_OVF   |
146                  SPI_FIFO_STS_TX_FIFO_UNR   |
147                  SPI_FIFO_STS_RX_FIFO_OVF   |
148                  SPI_FIFO_STS_RX_FIFO_UNR;
149    spi_bus->regs->fifo_status = fifo_status;
150
151    uint32_t command1 = spi_bus->regs->command1;
152    command1 |= (spi_bus->clock_mode << SPI_CMD1_MODE_SHIFT);
153    if (spi_bus->cs != NULL) {
154        // Use software chip select if spi_chipselect_fn is provided
155        command1 |= SPI_CMD1_CS_SW_HW;
156    }
157    command1 |= SPI_CMD1_TX_EN | SPI_CMD1_RX_EN;
158    command1 |= (8 - 1) << SPI_CMD1_BIT_LEN_SHIFT;
159    spi_bus->regs->command1 = command1;
160
161    uint32_t command2 = spi_bus->regs->command2;
162    command2 |= (CLK_TAP_DELAY & SPI_CMD2_RX_CLK_TAP_DELAY_MASK);
163    spi_bus->regs->command2 = command2;
164
165    uint32_t timing1 = spi_bus->regs->timing1;
166    timing1 |= (CS_SETUP_TIME << CS_SETUP_TIME_0_SHIFT);
167    timing1 |= (CS_HOLD_TIME << CS_HOLD_TIME_0_SHIFT);
168    spi_bus->regs->timing1 = timing1;
169
170    uint32_t dma_ctl = spi_bus->regs->dma_ctl;
171    dma_ctl |= SPI_IE_RX | SPI_IE_TX;
172    spi_bus->regs->dma_ctl = dma_ctl;
173
174    spi_bus->regs->xfer_status |= SPI_XFER_STS_RDY;
175
176    *ret_spi_bus = spi_bus;
177    return 0;
178}
179
180static void
181finish_spi_transfer(spi_bus_t* spi_bus) {
182    // Drain RX FIFO
183    size_t size = spi_bus->txsize + spi_bus->rxsize;
184    for (int i = 0; i < size; i++) {
185        uint32_t data_in = spi_bus->regs->rx_fifo;
186        if (spi_bus->rxbuf != NULL) {
187            spi_bus->rxbuf[i] = (uint8_t) (data_in & 0xFF);
188        }
189    }
190
191    spi_bus->regs->xfer_status |= SPI_XFER_STS_RDY;
192    spi_bus->in_progress = false;
193
194    // Release chip select
195    if (spi_bus->cs != NULL) {
196        spi_bus->cs(spi_bus->curr_slave, SPI_CS_RELAX);
197    }
198
199    spi_bus->cb(spi_bus, size, spi_bus->token);
200}
201
202void
203spi_handle_irq(spi_bus_t* spi_bus)
204{
205    if (spi_bus->regs->xfer_status & SPI_XFER_STS_RDY) {
206        finish_spi_transfer(spi_bus);
207    } else {
208        uint32_t fifo_status = spi_bus->regs->fifo_status;
209        ZF_LOGE("FIFO error, status = 0x%08x", fifo_status);
210
211        // Abort transfer
212        spi_bus->regs->command1 &= ~SPI_CMD1_GO;
213        // Clear FIFO status, flush FIFOs
214        fifo_status |= SPI_FIFO_STS_RX_FIFO_FLUSH | SPI_FIFO_STS_TX_FIFO_FLUSH;
215        spi_bus->regs->fifo_status = fifo_status;
216        // Re-initialize transfer status
217        spi_bus->regs->xfer_status |= SPI_XFER_STS_RDY;
218        spi_bus->in_progress = false;
219        // Release chip select
220        if (spi_bus->cs != NULL) {
221            spi_bus->cs(spi_bus->curr_slave, SPI_CS_RELAX);
222        }
223        // Indicate failure to user
224        spi_bus->cb(spi_bus, -1, spi_bus->token);
225    }
226}
227
228static void
229start_spi_transfer(spi_bus_t* spi_bus) {
230    // Assert chip select
231    if (spi_bus->cs != NULL) {
232        spi_bus->cs(spi_bus->curr_slave, SPI_CS_ASSERT);
233    }
234    size_t size = spi_bus->txsize + spi_bus->rxsize;
235    spi_bus->regs->dma_blk = size - 1;
236
237    // Load TX FIFO
238    for (int i = 0; i < size; i++) {
239        if (i < spi_bus->txsize) {
240            spi_bus->regs->tx_fifo = spi_bus->txbuf[i];
241        } else {
242            spi_bus->regs->tx_fifo = 0;
243        }
244    }
245
246    // Signal transfer to begin
247    spi_bus->regs->command1 |= SPI_CMD1_GO;
248}
249
250int
251spi_xfer(spi_bus_t* spi_bus, const void* txdata, size_t txcnt,
252         void* rxdata, size_t rxcnt, spi_callback_fn cb, void* token)
253{
254    if (spi_bus->in_progress) {
255        ZF_LOGE("SPI transaction in progress");
256        return -1;
257    }
258    if (txcnt + rxcnt > FIFO_SIZE) {
259        ZF_LOGE("SPI transaction size (%d) exceeds FIFO size (%d)", txcnt + rxcnt, FIFO_SIZE);
260        return -2;
261    }
262    if (cb == NULL) {
263        ZF_LOGE("Synchronous SPI transactions are not implemented");
264        return -3;
265    }
266
267    spi_bus->txbuf = (uint8_t*) txdata;
268    spi_bus->rxbuf = (uint8_t*) rxdata;
269    spi_bus->txsize = txcnt;
270    spi_bus->rxsize = rxcnt;
271    spi_bus->in_progress = true;
272    spi_bus->cb = cb;
273    spi_bus->token = token;
274
275    start_spi_transfer(spi_bus);
276    return 0;
277}
278
279void
280spi_prepare_transfer(spi_bus_t* spi_bus, const spi_slave_config_t* cfg)
281{
282    // TODO: implement support for multiple slaves
283    spi_bus->curr_slave = (spi_slave_config_t *)cfg;
284}
285