1 /* Copyright (C) 2012-2013, 2015 Czech Technical University in Prague
3 * This document contains proprietary information belonging to Czech
4 * Technical University in Prague. Passing on and copying of this
5 * document, and communication of its contents is not permitted
6 * without prior written authorization.
10 * Code based on Halcogen generated source code
15 #include "sys/ti_drv_dmm.h"
16 #include "drv/spi_def.h"
17 #include "drv/spi_tms570.h"
19 #define SPI_FLG_TXINT_m (1 << 9)
20 #define SPI_FLG_RXINT_m (1 << 8)
22 #define SPI_INT0_TXINTENA_m (1 << 9)
23 #define SPI_INT0_RXINTENA_m (1 << 8)
25 #define SPI_DAT1_CSHOLD_m (1 << 28)
27 typedef volatile struct spiBase {
28 uint32_t GCR0; /**< 0x0000: Global Control 0 */
29 #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
30 uint32_t GCR1 : 8U; /**< 0x0007: Global Control 1 */
31 uint32_t PD : 1U; /**< 0x0006: Power down bit */
33 uint32_t LB : 1U; /**< 0x0005: Loop back bit */
35 uint32_t ENA : 1U; /**< 0x0004: SPI Enable bit */
37 uint32_t INT0 : 16U; /**< 0x000A: Interrupt Enable bits */
38 uint32_t DMAREQEN : 1U; /**< 0x0009: DMA Request enable */
40 uint32_t ENAHIGHZ : 1U; /**< 0x0008: Enable HIGHZ outputs */
44 uint32_t ENA : 1U; /**< 0x0004: SPI Enable bit */
46 uint32_t LB : 1U; /**< 0x0005: Loop back bit */
48 uint32_t PD : 1U; /**< 0x0006: Power down bit */
49 uint32_t GCR1 : 8U; /**< 0x0007: Global Control 1 */
51 uint32_t ENAHIGHZ : 1U; /**< 0x0008: Enable HIGHZ outputs */
53 uint32_t DMAREQEN : 1U; /**< 0x0009: DMA Request enable */
54 uint32_t INT0 : 16U; /**< 0x000A: Interrupt Enable bits */
56 uint32_t LVL; /**< 0x000C: Interrupt Level */
57 #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
58 uint32_t FLG : 16U; /**< 0x0012: Interrupt flags */
60 uint32_t BUFINIT : 1U; /**< 0x0010: Buffer initialization active flag */
64 uint32_t BUFINIT : 1U; /**< 0x0010: Buffer initialization active flag */
66 uint32_t FLG : 16U; /**< 0x0012: Interrupt flags */
68 uint32_t PCFUN; /**< 0x0014: Function Pin Enable */
69 uint32_t PCDIR; /**< 0x0018: Pin Direction */
70 uint32_t PCDIN; /**< 0x001C: Pin Input Latch */
71 uint32_t PCDOUT; /**< 0x0020: Pin Output Latch */
72 uint32_t PCSET; /**< 0x0024: Output Pin Set */
73 uint32_t PCCLR; /**< 0x0028: Output Pin Clr */
74 uint32_t PCPDR; /**< 0x002C: Open Drain Output Enable */
75 uint32_t PCDIS; /**< 0x0030: Pullup/Pulldown Disable */
76 uint32_t PCPSL; /**< 0x0034: Pullup/Pulldown Selection */
77 uint32_t DAT0; /**< 0x0038: Transmit Data */
78 uint32_t DAT1; /**< 0x003C: Transmit Data with Format and Chip Select */
79 uint32_t BUF; /**< 0x0040: Receive Buffer */
80 uint32_t EMU; /**< 0x0044: Emulation Receive Buffer */
81 uint32_t DELAY; /**< 0x0048: Delays */
82 uint32_t CSDEF; /**< 0x004C: Default Chip Select */
83 uint32_t FMT0; /**< 0x0050: Data Format 0 */
84 uint32_t FMT1; /**< 0x0054: Data Format 1 */
85 uint32_t FMT2; /**< 0x0058: Data Format 2 */
86 uint32_t FMT3; /**< 0x005C: Data Format 3 */
87 uint32_t INTVECT0; /**< 0x0060: Interrupt Vector 0 */
88 uint32_t INTVECT1; /**< 0x0064: Interrupt Vector 1 */
89 uint32_t SRSEL; /**< 0x0068: Slew Rate Select */
91 uint32_t PMCTRL; /**< 0x006C: Parallel Mode Control */
92 #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
93 uint32_t MIBSPIE : 16U; /**< 0x0072: MibSPI Enable */
94 uint32_t RAMACCESS : 16U; /**< 0x0070: RX Ram Write Access Enable */
96 uint32_t RAMACCESS : 16U; /**< 0x0070: RX Ram Write Access Enable */
97 uint32_t MIBSPIE : 16U; /**< 0x0072: MibSPI Enable */
100 uint32_t RESERVED[48U]; /**< 0x006C to 0x0130: Reserved */
101 uint32_t IOLPKTSTCR; /**< 0x0134: IO loopback */
104 #define spi_compat_REG2 ((spiBASE_compat_t *)0xFFF7F600U)
105 #define spi_compat_REG4 ((spiBASE_compat_t *)0xFFF7FA00U)
106 #define mibspi_compat_REG1 ((spiBASE_compat_t *)0xFFF7F400U)
107 #define mibspi_compat_REG3 ((spiBASE_compat_t *)0xFFF7F800U)
108 #define mibspi_compat_REG5 ((spiBASE_compat_t *)0xFFF7FC00U) /* NOT USED ON RPP BOARD */
111 struct spi_tms570_iface {
113 spiBASE_compat_t *reg; /* Base Reg. for SPI device register array */
114 unsigned txcnt; /* No. of transfered bytes for msg_act */
115 unsigned rxcnt; /* No. of received bytes for msg_act */
116 spi_dev_t *spi_devs; /* Pointer to table holding information about SPI devices bound to the interface */
117 uint32_t transfer_ctrl; /* Transfer configuration -- upper 16 bits of SPIDAT1 register */
118 /* TODO: Add FMT description here if we need different formats */
121 spi_tms570_iface_t spi_iface[5] = {
122 [SPI_IFACE1] = { .reg = mibspi_compat_REG1, },
123 [SPI_IFACE2] = { .reg = spi_compat_REG2, },
124 [SPI_IFACE3] = { .reg = mibspi_compat_REG3, },
125 [SPI_IFACE4] = { .reg = spi_compat_REG4, },
126 [SPI_IFACE5] = { .reg = mibspi_compat_REG5, },
129 spi_drv_t *spi_tms570_get_iface(enum spi_device dev)
131 return &spi_iface[spi_devs[dev].iface].spi_drv;
134 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
137 Universal piece of code initializing SPI or MibSPI
138 devices in "compatibility" mode.
139 8 CS pins are initialized on each device -- even if
140 it does not have so much of them.
141 ENA register is set even on SPI devices which do not have it --
142 this should not be an issue
144 static void spiInit(spiBASE_compat_t *spiREG)
146 /** bring SPI out of reset */
149 /** SPI master mode and clock configuration */
150 spiREG->GCR1 = (1 << 1) /* CLOKMOD */
153 /** SPI enable pin configuration */
154 spiREG->ENAHIGHZ = 0; /* ENABLE HIGHZ */
157 spiREG->DELAY = (0 << 24) /* C2TDELAY */
158 | (0 << 16) /* T2CDELAY */
159 | (0 << 8) /* T2EDELAY */
162 /** - Data Format 0 */
163 /* TODO: Set the formats from spi_tms570_iface_t if we need different formats */
164 spiREG->FMT0 = (0 << 24) /* wdelay */
165 | (0 << 23) /* parity Polarity */
166 | (0 << 22) /* parity enable */
167 | (0 << 21) /* wait on enable */
168 | (0 << 20) /* shift direction */
169 | (0 << 17) /* clock polarity */
170 | (0 << 16) /* clock phase */
171 | ((RPP_VCLK1_FREQ / SPI_BR_FORMAT0 - 1 ) << 8) /* baudrate prescale */
172 | 8; /* data word length */
174 /** - Data Format 1 */
175 spiREG->FMT1 = (0 << 24) /* wdelay */
176 | (0 << 23) /* parity Polarity */
177 | (0 << 22) /* parity enable */
178 | (0 << 21) /* wait on enable */
179 | (0 << 20) /* shift direction */
180 | (0 << 17) /* clock polarity */
181 | (1 << 16) /* clock phase */
182 | ((RPP_VCLK1_FREQ / SPI_BR_FORMAT1 - 1 ) << 8) /* baudrate prescale */
183 | 8; /* data word length */
185 /** - Data Format 2 */
186 spiREG->FMT2 = (0 << 24) /* wdelay */
187 | (0 << 23) /* parity Polarity */
188 | (0 << 22) /* parity enable */
189 | (0 << 21) /* wait on enable */
190 | (0 << 20) /* shift direction */
191 | (0 << 17) /* clock polarity */
192 | (0 << 16) /* clock phase */
193 | ((RPP_VCLK1_FREQ / SPI_BR_FORMAT2 - 1 ) << 8) /* baudrate prescale */
194 | 8; /* data word length */
196 /** - Data Format 3 */
197 spiREG->FMT3 = (0 << 24) /* wdelay */
198 | (0 << 23) /* parity Polarity */
199 | (0 << 22) /* parity enable */
200 | (0 << 21) /* wait on enable */
201 | (0 << 20) /* shift direction */
202 | (0 << 17) /* clock polarity */
203 | (0 << 16) /* clock phase */
204 | ((RPP_VCLK1_FREQ / SPI_BR_FORMAT3 - 1 ) << 8) /* baudrate prescale */
205 | 8; /* data word length */
207 /** - set interrupt levels */
208 spiREG->LVL = (0 << 9) /* TXINT */
209 | (0 << 8) /* RXINT */
210 | (0 << 6) /* OVRNINT */
211 | (0 << 4) /* BITERR */
212 | (0 << 3) /* DESYNC */
213 | (0 << 2) /* PARERR */
214 | (0 << 1) /* TIMEOUT */
217 /** - clear any pending interrupts */
218 spiREG->FLG = 0xFFFFU;
220 /** - enable interrupts */
221 spiREG->INT0 = (0 << 9) /* TXINT */
222 | (0 << 8) /* RXINT */
223 | (0 << 6) /* OVRNINT */
224 | (0 << 4) /* BITERR */
225 | (0 << 3) /* DESYNC */
226 | (0 << 2) /* PARERR */
227 | (0 << 1) /* TIMEOUT */
230 /** initialize SPI Port */
232 /** - SPI Port output values */
233 spiREG->PCDOUT = 1 /* SCS[0] */
234 | (1 << 1) /* SCS[1] */
235 | (1 << 2) /* SCS[2] */
236 | (1 << 3) /* SCS[3] */
237 | (1 << 4) /* SCS[4] */
238 | (1 << 5) /* SCS[5] */
239 | (1 << 6) /* SCS[6] */
240 | (1 << 7) /* SCS[7] */
243 | (0 << 10) /* SIMO */
244 | (0 << 11); /* SOMI */
246 /** - SPI Port direction */
247 spiREG->PCDIR = 1 /* SCS[0] */
248 | (1 << 1) /* SCS[1] */
249 | (1 << 2) /* SCS[2] */
250 | (1 << 3) /* SCS[3] */
251 | (1 << 4) /* SCS[4] */
252 | (1 << 5) /* SCS[5] */
253 | (1 << 6) /* SCS[6] */
254 | (1 << 7) /* SCS[7] */
257 | (1 << 10) /* SIMO */
258 | (0 << 11); /* SOMI */
260 /** - SPI Port open drain enable */
261 spiREG->PCPDR = 0 /* SCS[0] */
262 | (0 << 1) /* SCS[1] */
263 | (0 << 2) /* SCS[2] */
264 | (0 << 3) /* SCS[3] */
265 | (0 << 4) /* SCS[4] */
266 | (0 << 5) /* SCS[5] */
267 | (0 << 6) /* SCS[6] */
268 | (0 << 7) /* SCS[7] */
271 | (0 << 10) /* SIMO */
272 | (0 << 11); /* SOMI */
274 /** - SPI Port pullup / pulldown selection */
275 spiREG->PCPSL = 1 /* SCS[0] */
276 | (1 << 1) /* SCS[1] */
277 | (1 << 2) /* SCS[2] */
278 | (1 << 3) /* SCS[3] */
279 | (1 << 4) /* SCS[4] */
280 | (1 << 5) /* SCS[5] */
281 | (1 << 6) /* SCS[6] */
282 | (1 << 7) /* SCS[7] */
285 | (1 << 10) /* SIMO */
286 | (1 << 11); /* SOMI */
288 /** - SPI Port pullup / pulldown enable*/
289 spiREG->PCDIS = 0 /* SCS[0] */
290 | (0 << 1) /* SCS[1] */
291 | (0 << 2) /* SCS[2] */
292 | (0 << 3) /* SCS[3] */
293 | (0 << 4) /* SCS[4] */
294 | (0 << 5) /* SCS[5] */
295 | (0 << 6) /* SCS[6] */
296 | (0 << 7) /* SCS[7] */
299 | (0 << 10) /* SIMO */
300 | (0 << 11); /* SOMI */
302 /* SPI set all pins to functional */
303 spiREG->PCFUN = 1 /* SCS[0] */
304 | (1 << 1) /* SCS[1] */
305 | (1 << 2) /* SCS[2] */
306 | (1 << 3) /* SCS[3] */
307 | (1 << 4) /* SCS[4] */
308 | (1 << 5) /* SCS[5] */
309 | (1 << 6) /* SCS[6] */
310 | (1 << 7) /* SCS[7] */
313 | (1 << 10) /* SIMO */
314 | (1 << 11); /* SOMI */
316 /* Default CS logic levels */
317 spiREG->CSDEF = 0xFF;
319 /** Set MibSPI devices into compatibility mode --
320 "SPI" devices will hopefully ignore this */
321 spiREG->MIBSPIE = 0U;
323 /** - Finally start SPI */
327 static void init_iface(spi_tms570_iface_t *iface)
330 iface->spi_drv.ctrl_fnc = spi_tms570_ctrl_fnc;
331 spi_rq_queue_init_head(&(iface->spi_drv));
332 iface->spi_drv.msg_act = NULL;
333 iface->spi_drv.flags = 0;
336 void spi_tms570_init()
340 for (i = 0; i < ARRAY_SIZE(spi_iface); i++)
341 init_iface(&spi_iface[i]);
343 //dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
344 //dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
348 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
350 spi_tms570_iface_t *tms570_drv =
351 UL_CONTAINEROF(ifc, spi_tms570_iface_t, spi_drv);
354 case SPI_CTRL_WAKE_RQ:
355 if (spi_rq_queue_is_empty(ifc))
358 tms570_drv->reg->INT0 = SPI_INT0_TXINTENA_m;
359 // Enable TXINT (Causes an interrupt
360 // to be generated every time data is written to the shift
361 // register, so that the next word can be written to TXBUF.
362 // (=transmitter empty interrupt)
363 // Setting this bit will generate an interrupt if the
364 // TXINTFLG bit (SPI Flag Register (SPIFLG)[9]) is set to 1.;
365 // An interrupt request will be generated as soon as this
376 /* -------------------------------------------------------------------------- */
380 void spi_tms570_isr(int spi_ifc, uint32_t flags)
383 spi_tms570_iface_t *iface = &spi_iface[spi_ifc];
384 const spi_dev_t *dev;
385 spi_isr_lock_level_t saveif;
391 unsigned int rx_data;
394 if (flags & SPI_FLG_TXINT_m) {
396 msg = iface->spi_drv.msg_act;
397 if (!msg) { /* Is there any MSG being processed? */
398 /* If not, get one from a queue */
399 spi_isr_lock(saveif);
400 msg = iface->spi_drv.msg_act =
401 spi_rq_queue_first(&iface->spi_drv);
402 spi_isr_unlock(saveif);
404 if (!msg) { /* Nothing to process */
405 volatile unsigned int dummy_read;
406 /* Disable TXEMPTY IRQ */
407 iface->reg->INT0 = 0x00;
408 iface->reg->FLG = 0x00;
409 dummy_read = iface->reg->BUF;
410 // FIXME "INT |= " with disabled IRQ ??
416 dev = &spi_devs[msg->dev];
418 iface->transfer_ctrl =
420 | (dev->wdel & 0x1) << 26
421 | (dev->cshold & 0x1) << 28
422 | (dev->dfsel & 0x3) << 24;
424 #if defined(TARGET_TMS570_RPP)
425 /* GPIO CS -- setting the multiplexer */
427 switch (cs & 0xFF00) {
429 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
430 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
433 dmmREG->PC4 = (1 << DMM_DATA5); /* Set to H */
434 dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
437 dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
438 dmmREG->PC4 = (1 << DMM_DATA6); /* Set to H */
445 rq_len = msg->rq_len;
446 rxcnt = iface->rxcnt;
447 txcnt = iface->txcnt;
448 /* RX/TX transfers */
450 /* Receive all the incoming data */
451 while (iface->reg->FLG & SPI_FLG_RXINT_m) {
452 rx_data = iface->reg->BUF;
454 if (msg->rx_buf && (rxcnt < rq_len)) {
455 /* This relies on all FMTs having 8 bit CHARLEN */
456 msg->rx_buf[rxcnt++] = rx_data & 0xFF;
463 /* Tx buffer full or nothing to send */
464 stop_fl = ((txcnt >= rq_len) ||
465 (!(iface->reg->FLG & SPI_FLG_TXINT_m)));
469 /* Make it possible to write "empty data"
470 for "read transfers" */
472 /* This relies on all FMTs having 8 bit CHARLEN */
473 val_to_wr = msg->tx_buf[txcnt++];
479 if (txcnt == rq_len) /* Disable CS after last byte of the transfer */
480 iface->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
483 (uint32_t)(iface->transfer_ctrl | val_to_wr);
485 /* We just received something */
486 if (iface->reg->FLG & SPI_FLG_RXINT_m)
490 iface->rxcnt = rxcnt;
491 iface->txcnt = txcnt;
493 if ((rxcnt >= rq_len) ||
494 (!msg->rx_buf && (txcnt >= rq_len) &&
495 !(iface->reg->FLG & SPI_FLG_RXINT_m))) { // FIXME
497 /* Sending of the message successfully finished */
498 spi_isr_lock(saveif);
499 spi_rq_queue_del_item(msg);
500 msg->flags |= SPI_MSG_FINISHED;
501 iface->spi_drv.msg_act = NULL;
502 spi_isr_unlock(saveif);
504 msg->callback(&iface->spi_drv,
505 SPI_MSG_FINISHED, msg);
510 iface->reg->INT0 = SPI_INT0_TXINTENA_m;
512 iface->reg->INT0 = SPI_INT0_RXINTENA_m;
518 #pragma INTERRUPT(spi2LowLevelInterrupt, IRQ)
519 void spi2LowLevelInterrupt(void)
521 uint32_t flags = spi_compat_REG2->FLG; // & (~spiREG2->LVL & 0x035F);
523 spi_tms570_isr(2 - 1, flags);
526 #pragma INTERRUPT(spi2HighLevelInterrupt, IRQ)
527 void spi2HighLevelInterrupt(void)
529 uint32_t flags = spi_compat_REG2->FLG; // & (~spiREG2->LVL & 0x035F);
531 spi_tms570_isr(2 - 1, flags);
534 #pragma INTERRUPT(spi4LowLevelInterrupt, IRQ)
535 void spi4LowLevelInterrupt(void)
537 uint32_t flags = spi_compat_REG4->FLG; // & (~spiREG4->LVL & 0x035F);
539 spi_tms570_isr(4 - 1, flags);
542 #pragma INTERRUPT(spi4HighLevelInterrupt, IRQ)
543 void spi4HighLevelInterrupt(void)
545 uint32_t flags = spi_compat_REG4->FLG; // & (~spiREG4->LVL & 0x035F);
547 spi_tms570_isr(4 - 1, flags);
550 #pragma INTERRUPT(mibspi1HighLevelInterrupt, IRQ)
551 void mibspi1HighLevelInterrupt(void)
553 uint32_t flags = mibspi_compat_REG1->FLG; // & (~mibspiREG1->LVL & 0x035F);
555 spi_tms570_isr(1 - 1, flags);
558 #pragma INTERRUPT(mibspi1LowLevelInterrupt, IRQ)
559 void mibspi1LowLevelInterrupt(void)
561 uint32_t flags = mibspi_compat_REG1->FLG; // & (~mibspiREG1->LVL & 0x035F);
563 spi_tms570_isr(1 - 1, flags);
566 #pragma INTERRUPT(mibspi3HighInterruptLevel, IRQ)
567 void mibspi3HighInterruptLevel(void)
569 uint32_t flags = mibspi_compat_REG3->FLG; // & (~mibspiREG3->LVL & 0x035F);
571 spi_tms570_isr(3 - 1, flags);
574 #pragma INTERRUPT(mibspi3LowLevelInterrupt, IRQ)
575 void mibspi3LowLevelInterrupt(void)
577 uint32_t flags = mibspi_compat_REG3->FLG; // & (~mibspiREG3->LVL & 0x035F);
579 spi_tms570_isr(3 - 1, flags);