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