1 /*
2  * Copyright (c) 2015-2018, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 #include <stdbool.h>
33 #include <stddef.h>
34 #include <stdint.h>
35 
36 #include <ti/devices/cc32xx/inc/hw_mcspi.h>
37 #include <ti/devices/cc32xx/inc/hw_types.h>
38 #include <ti/devices/cc32xx/inc/hw_memmap.h>
39 #include <ti/devices/cc32xx/inc/hw_udma.h>
40 #include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
41 #include <ti/devices/cc32xx/driverlib/rom.h>
42 #include <ti/devices/cc32xx/driverlib/rom_map.h>
43 #include <ti/devices/cc32xx/driverlib/prcm.h>
44 #include <ti/devices/cc32xx/driverlib/spi.h>
45 #include <ti/devices/cc32xx/driverlib/udma.h>
46 
47 #include <ti/drivers/dma/UDMACC32XX.h>
48 #include <ti/drivers/dpl/HwiP.h>
49 #include <ti/drivers/dpl/SemaphoreP.h>
50 #include <ti/drivers/Power.h>
51 #include <ti/drivers/power/PowerCC32XX.h>
52 #include <ti/drivers/spi/SPICC32XXDMA.h>
53 
54 #define MAX_DMA_TRANSFER_AMOUNT (1024)
55 
56 #define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0)
57 #define PAD_RESET_STATE 0xC61
58 
59 void SPICC32XXDMA_close(SPI_Handle handle);
60 int_fast16_t SPICC32XXDMA_control(SPI_Handle handle, uint_fast16_t cmd,
61     void *arg);
62 void SPICC32XXDMA_init(SPI_Handle handle);
63 SPI_Handle SPICC32XXDMA_open(SPI_Handle handle, SPI_Params *params);
64 bool SPICC32XXDMA_transfer(SPI_Handle handle, SPI_Transaction *transaction);
65 void SPICC32XXDMA_transferCancel(SPI_Handle handle);
66 
67 /* SPI function table for SPICC32XXDMA implementation */
68 const SPI_FxnTable SPICC32XXDMA_fxnTable = {
69     SPICC32XXDMA_close,
70     SPICC32XXDMA_control,
71     SPICC32XXDMA_init,
72     SPICC32XXDMA_open,
73     SPICC32XXDMA_transfer,
74     SPICC32XXDMA_transferCancel
75 };
76 
77 static const uint32_t mode[] = {
78     SPI_MODE_MASTER,
79     SPI_MODE_SLAVE
80 };
81 
82 /*
83  * This lookup table is used to configure the DMA channels for the appropriate
84  * (8bit, 16bit or 32bit) transfer sizes.
85  * Table for an SPI DMA RX channel.
86  */
87 static const uint32_t dmaRxConfig[] = {
88     UDMA_SIZE_8  | UDMA_SRC_INC_NONE | UDMA_DST_INC_8  | UDMA_ARB_1,
89     UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1,
90     UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_ARB_1
91 };
92 
93 /*
94  * This lookup table is used to configure the DMA channels for the appropriate
95  * (8bit, 16bit or 32bit) transfer sizes.
96  * Table for an SPI DMA TX channel
97  */
98 static const uint32_t dmaTxConfig[] = {
99     UDMA_SIZE_8  | UDMA_SRC_INC_8  | UDMA_DST_INC_NONE | UDMA_ARB_1,
100     UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_1,
101     UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE | UDMA_ARB_1
102 };
103 
104 /*
105  * This lookup table is used to configure the DMA channels for the appropriate
106  * (8bit, 16bit or 32bit) transfer sizes when either txBuf or rxBuf are NULL.
107  */
108 static const uint32_t dmaNullConfig[] = {
109     UDMA_SIZE_8  | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1,
110     UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1,
111     UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1
112 };
113 
114 /*
115  *  ======== blockingTransferCallback ========
116  */
blockingTransferCallback(SPI_Handle handle,SPI_Transaction * transaction)117 static void blockingTransferCallback(SPI_Handle handle,
118     SPI_Transaction *transaction)
119 {
120     SPICC32XXDMA_Object *object = handle->object;
121 
122     SemaphoreP_post(object->transferComplete);
123 }
124 
125 /*
126  *  ======== configDMA ========
127  *  This functions configures the transmit and receive DMA channels for a given
128  *  SPI_Handle and SPI_Transaction
129  */
configDMA(SPICC32XXDMA_Object * object,SPICC32XXDMA_HWAttrsV1 const * hwAttrs,SPI_Transaction * transaction)130 static void configDMA(SPICC32XXDMA_Object *object,
131     SPICC32XXDMA_HWAttrsV1 const *hwAttrs, SPI_Transaction *transaction)
132 {
133     uintptr_t  key;
134     void      *buf;
135     uint32_t   channelControlOptions;
136     uint8_t    dataFrameSizeInBytes;
137     uint8_t    optionsIndex;
138 
139     /* DMA options used vary according to data size. */
140     if (object->dataSize < 9) {
141         optionsIndex = 0;
142         dataFrameSizeInBytes = sizeof(uint8_t);
143     }
144     else if (object->dataSize < 17) {
145         optionsIndex = 1;
146         dataFrameSizeInBytes = sizeof(uint16_t);;
147     }
148     else {
149         optionsIndex = 2;
150         dataFrameSizeInBytes = sizeof(uint32_t);
151     }
152 
153     /*
154      * The DMA has a max transfer amount of 1024.  If the transaction is
155      * greater; we must transfer it in chunks.  object->amtDataXferred has
156      * how much data has already been sent.
157      */
158     if ((transaction->count - object->amtDataXferred) > MAX_DMA_TRANSFER_AMOUNT) {
159         object->currentXferAmt = MAX_DMA_TRANSFER_AMOUNT;
160     }
161     else {
162         object->currentXferAmt = (transaction->count - object->amtDataXferred);
163     }
164 
165     if (transaction->txBuf) {
166         channelControlOptions = dmaTxConfig[optionsIndex];
167         /*
168          * Add an offset for the amount of data transfered.  The offset is
169          * calculated by: object->amtDataXferred * (dataFrameSizeInBytes).
170          * This accounts for 8, 16 or 32-bit sized transfers.
171          */
172         buf = (void *) ((uint32_t) transaction->txBuf +
173             ((uint32_t) object->amtDataXferred * dataFrameSizeInBytes));
174     }
175     else {
176         channelControlOptions = dmaNullConfig[optionsIndex];
177         *hwAttrs->scratchBufPtr = hwAttrs->defaultTxBufValue;
178         buf = hwAttrs->scratchBufPtr;
179     }
180 
181     /* Setup the TX transfer characteristics & buffers */
182     MAP_uDMAChannelControlSet(hwAttrs->txChannelIndex | UDMA_PRI_SELECT,
183         channelControlOptions);
184     MAP_uDMAChannelAttributeDisable(hwAttrs->txChannelIndex,
185         UDMA_ATTR_ALTSELECT);
186     MAP_uDMAChannelTransferSet(hwAttrs->txChannelIndex | UDMA_PRI_SELECT,
187         UDMA_MODE_BASIC, buf, (void *) (hwAttrs->baseAddr + MCSPI_O_TX0),
188         object->currentXferAmt);
189 
190     if (transaction->rxBuf) {
191         channelControlOptions = dmaRxConfig[optionsIndex];
192         /*
193          * Add an offset for the amount of data transfered.  The offset is
194          * calculated by: object->amtDataXferred * (dataFrameSizeInBytes).
195          * This accounts for 8 or 16-bit sized transfers.
196          */
197         buf = (void *) ((uint32_t) transaction->rxBuf +
198             ((uint32_t) object->amtDataXferred * dataFrameSizeInBytes));
199     }
200     else {
201         channelControlOptions = dmaNullConfig[optionsIndex];
202         buf = hwAttrs->scratchBufPtr;
203     }
204 
205     /* Setup the RX transfer characteristics & buffers */
206     MAP_uDMAChannelControlSet(hwAttrs->rxChannelIndex | UDMA_PRI_SELECT,
207         channelControlOptions);
208     MAP_uDMAChannelAttributeDisable(hwAttrs->rxChannelIndex,
209         UDMA_ATTR_ALTSELECT);
210     MAP_uDMAChannelTransferSet(hwAttrs->rxChannelIndex | UDMA_PRI_SELECT,
211         UDMA_MODE_BASIC, (void *) (hwAttrs->baseAddr + MCSPI_O_RX0), buf,
212         object->currentXferAmt);
213 
214     /* A lock is needed because we are accessing shared uDMA memory */
215     key = HwiP_disable();
216 
217     /*
218      * DMA channels 30 and 31 are connected to the SPI peripheral by default.
219      * If someone hasn't remapped them to something else already, we remap
220      * them to SW.
221      */
222     if (!(HWREG(UDMA_BASE + UDMA_O_CHMAP3) & UDMA_CHMAP3_CH30SEL_M)) {
223         MAP_uDMAChannelAssign(UDMA_CH30_SW);
224     }
225     if (!(HWREG(UDMA_BASE + UDMA_O_CHMAP3) & UDMA_CHMAP3_CH31SEL_M)) {
226         MAP_uDMAChannelAssign(UDMA_CH31_SW);
227     }
228 
229     /* Assign the requested DMA channels */
230     MAP_uDMAChannelAssign(hwAttrs->rxChannelIndex);
231     MAP_uDMAChannelAssign(hwAttrs->txChannelIndex);
232 
233     /* Enable DMA to generate interrupt on SPI peripheral */
234     MAP_SPIDmaEnable(hwAttrs->baseAddr, SPI_RX_DMA | SPI_TX_DMA);
235     MAP_SPIIntClear(hwAttrs->baseAddr, SPI_INT_DMARX);
236     MAP_SPIIntEnable(hwAttrs->baseAddr, SPI_INT_DMARX);
237     MAP_SPIWordCountSet(hwAttrs->baseAddr, object->currentXferAmt);
238 
239     /* Enable channels & start DMA transfers */
240     MAP_uDMAChannelEnable(hwAttrs->txChannelIndex);
241     MAP_uDMAChannelEnable(hwAttrs->rxChannelIndex);
242 
243     HwiP_restore(key);
244 
245     MAP_SPIEnable(hwAttrs->baseAddr);
246     MAP_SPICSEnable(hwAttrs->baseAddr);
247 }
248 
249 /*
250  *  ======== getDmaRemainingXfers ========
251  */
getDmaRemainingXfers(SPICC32XXDMA_HWAttrsV1 const * hwAttrs)252 static inline uint32_t getDmaRemainingXfers(SPICC32XXDMA_HWAttrsV1 const *hwAttrs) {
253     uint32_t          controlWord;
254     tDMAControlTable *controlTable;
255 
256     controlTable = MAP_uDMAControlBaseGet();
257     controlWord = controlTable[(hwAttrs->rxChannelIndex & 0x3f)].ulControl;
258 
259     return (((controlWord & UDMA_CHCTL_XFERSIZE_M) >> 4) + 1);
260 }
261 
262 /*
263  *  ======== getPowerMgrId ========
264  */
getPowerMgrId(uint32_t baseAddr)265 static uint16_t getPowerMgrId(uint32_t baseAddr)
266 {
267     switch (baseAddr) {
268         case GSPI_BASE:
269             return (PowerCC32XX_PERIPH_GSPI);
270         case LSPI_BASE:
271             return (PowerCC32XX_PERIPH_LSPI);
272         default:
273             return (~0);
274     }
275 }
276 
277 /*
278  *  ======== initHw ========
279  */
initHw(SPICC32XXDMA_Object * object,SPICC32XXDMA_HWAttrsV1 const * hwAttrs)280 static void initHw(SPICC32XXDMA_Object *object,
281     SPICC32XXDMA_HWAttrsV1 const *hwAttrs)
282 {
283     /*
284      * SPI peripheral should remain disabled until a transfer is requested.
285      * This is done to prevent the RX FIFO from gathering data from other
286      * transfers.
287      */
288     MAP_SPICSDisable(hwAttrs->baseAddr);
289     MAP_SPIDisable(hwAttrs->baseAddr);
290     MAP_SPIReset(hwAttrs->baseAddr);
291 
292     MAP_SPIConfigSetExpClk(hwAttrs->baseAddr,
293         MAP_PRCMPeripheralClockGet(hwAttrs->spiPRCM), object->bitRate,
294         mode[object->spiMode], object->frameFormat,
295         (hwAttrs->csControl | hwAttrs->pinMode | hwAttrs->turboMode |
296         hwAttrs->csPolarity | ((object->dataSize - 1) << 7)));
297 
298     MAP_SPIFIFOEnable(hwAttrs->baseAddr, SPI_RX_FIFO | SPI_TX_FIFO);
299     MAP_SPIFIFOLevelSet(hwAttrs->baseAddr, object->txFifoTrigger,
300         object->rxFifoTrigger);
301 }
302 
303 /*
304  *  ======== postNotifyFxn ========
305  */
postNotifyFxn(unsigned int eventType,uintptr_t eventArg,uintptr_t clientArg)306 static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
307     uintptr_t clientArg)
308 {
309     SPICC32XXDMA_Object          *object = ((SPI_Handle) clientArg)->object;
310     SPICC32XXDMA_HWAttrsV1 const *hwAttrs = ((SPI_Handle) clientArg)->hwAttrs;
311 
312     initHw(object, hwAttrs);
313 
314     return (Power_NOTIFYDONE);
315 }
316 
317 /*
318  *  ======== spiHwiFxn ========
319  */
spiHwiFxn(uintptr_t arg)320 static void spiHwiFxn(uintptr_t arg)
321 {
322     uint32_t                      intFlags;
323     SPI_Transaction              *msg;
324     SPICC32XXDMA_Object          *object = ((SPI_Handle)arg)->object;
325     SPICC32XXDMA_HWAttrsV1 const *hwAttrs = ((SPI_Handle)arg)->hwAttrs;
326 
327     /*
328      * Although the DMATX interrupt is not used by this driver, it seems like
329      * it is still triggering DMA interrupts.  The code below will clear &
330      * disable the interrupt thus reducing the amount of spurious interrupts.
331      */
332     intFlags = MAP_SPIIntStatus(hwAttrs->baseAddr, false);
333     if (intFlags & SPI_INT_DMATX) {
334         MAP_SPIIntDisable(hwAttrs->baseAddr, SPI_INT_DMATX);
335         MAP_SPIIntClear(hwAttrs->baseAddr, SPI_INT_DMATX);
336     }
337 
338     if (MAP_uDMAChannelIsEnabled(hwAttrs->rxChannelIndex)) {
339         /* DMA has not completed if the channel is still enabled */
340         return;
341     }
342 
343     /* RX DMA channel has completed; disable peripheral */
344     MAP_SPIDmaDisable(hwAttrs->baseAddr, SPI_RX_DMA | SPI_TX_DMA);
345     MAP_SPIIntDisable(hwAttrs->baseAddr, SPI_INT_DMARX);
346     MAP_SPIIntClear(hwAttrs->baseAddr, SPI_INT_DMARX);
347     MAP_SPICSDisable(hwAttrs->baseAddr);
348     MAP_SPIDisable(hwAttrs->baseAddr);
349 
350     if (object->transaction->count - object->amtDataXferred >
351         MAX_DMA_TRANSFER_AMOUNT) {
352         /* Data still remaining, configure another DMA transfer */
353         object->amtDataXferred += object->currentXferAmt;
354 
355         configDMA(object, hwAttrs, object->transaction);
356     }
357     else {
358         /* All data sent; set status, perform callback & return */
359         object->transaction->status = SPI_TRANSFER_COMPLETED;
360 
361         /* Release constraint since transaction is done */
362         Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
363 
364         /*
365          * Use a temporary transaction pointer in case the callback function
366          * attempts to perform another SPI_transfer call
367          */
368         msg = object->transaction;
369 
370         /* Indicate we are done with this transfer */
371         object->transaction = NULL;
372 
373         object->transferCallbackFxn((SPI_Handle) arg, msg);
374     }
375 }
376 
377 /*
378  *  ======== spiPollingTransfer ========
379  */
spiPollingTransfer(SPICC32XXDMA_Object * object,SPICC32XXDMA_HWAttrsV1 const * hwAttrs,SPI_Transaction * transaction)380 static inline void spiPollingTransfer(SPICC32XXDMA_Object *object,
381     SPICC32XXDMA_HWAttrsV1 const *hwAttrs, SPI_Transaction *transaction)
382 {
383     uint8_t   increment;
384     uint32_t  dummyBuffer;
385     size_t    transferCount;
386     void     *rxBuf;
387     void     *txBuf;
388 
389     if (transaction->rxBuf) {
390         rxBuf = transaction->rxBuf;
391     }
392     else {
393         rxBuf = hwAttrs->scratchBufPtr;
394     }
395 
396     if (transaction->txBuf) {
397         txBuf = transaction->txBuf;
398     }
399     else {
400         *hwAttrs->scratchBufPtr = hwAttrs->defaultTxBufValue;
401         txBuf = hwAttrs->scratchBufPtr;
402     }
403 
404     if (object->dataSize < 9) {
405         increment = sizeof(uint8_t);
406     }
407     else if (object->dataSize < 17) {
408         increment = sizeof(uint16_t);
409     }
410     else {
411         increment = sizeof(uint32_t);
412     }
413 
414     transferCount = transaction->count;
415 
416     /*
417      * Start the polling transfer - we MUST set word count to 0; not doing so
418      * will raise spurious RX interrupts flags (though interrupts are not
419      * enabled).
420      */
421     MAP_SPIWordCountSet(hwAttrs->baseAddr, 0);
422     MAP_SPIEnable(hwAttrs->baseAddr);
423     MAP_SPICSEnable(hwAttrs->baseAddr);
424 
425     while (transferCount--) {
426         if (object->dataSize < 9) {
427             MAP_SPIDataPut(hwAttrs->baseAddr, *((uint8_t *) txBuf));
428             MAP_SPIDataGet(hwAttrs->baseAddr, (unsigned long *)&dummyBuffer);
429             *((uint8_t *) rxBuf) = (uint8_t) dummyBuffer;
430         }
431         else if (object->dataSize < 17) {
432             MAP_SPIDataPut(hwAttrs->baseAddr, *((uint16_t *) txBuf));
433             MAP_SPIDataGet(hwAttrs->baseAddr, (unsigned long *) &dummyBuffer);
434             *((uint16_t *) rxBuf) = (uint16_t) dummyBuffer;
435         }
436         else {
437             MAP_SPIDataPut(hwAttrs->baseAddr, *((uint32_t *) txBuf));
438             MAP_SPIDataGet(hwAttrs->baseAddr, (unsigned long * ) rxBuf);
439         }
440 
441         /* Only increment source & destination if buffers were provided */
442         if (transaction->rxBuf) {
443             rxBuf = (void *) (((uint32_t) rxBuf) + increment);
444         }
445         if (transaction->txBuf) {
446             txBuf = (void *) (((uint32_t) txBuf) + increment);
447         }
448     }
449 
450     MAP_SPICSDisable(hwAttrs->baseAddr);
451     MAP_SPIDisable(hwAttrs->baseAddr);
452 }
453 
454 /*
455  *  ======== SPICC32XXDMA_close ========
456  */
SPICC32XXDMA_close(SPI_Handle handle)457 void SPICC32XXDMA_close(SPI_Handle handle)
458 {
459     uint32_t                      padRegister;
460     SPICC32XXDMA_Object          *object = handle->object;
461     SPICC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
462 
463     MAP_SPICSDisable(hwAttrs->baseAddr);
464     MAP_SPIDisable(hwAttrs->baseAddr);
465     MAP_SPIFIFODisable(hwAttrs->baseAddr, SPI_RX_FIFO | SPI_TX_FIFO);
466 
467     /* Release power dependency on SPI. */
468     Power_releaseDependency(getPowerMgrId(hwAttrs->baseAddr));
469     Power_unregisterNotify(&(object->notifyObj));
470 
471     if (object->hwiHandle) {
472         HwiP_delete(object->hwiHandle);
473         object->hwiHandle = NULL;
474     }
475     if (object->transferComplete) {
476         SemaphoreP_delete(object->transferComplete);
477         object->transferComplete = NULL;
478     }
479 
480     if (object->dmaHandle) {
481         UDMACC32XX_close(object->dmaHandle);
482         object->dmaHandle = NULL;
483     }
484 
485     /* Restore pin pads to their reset states */
486     if (hwAttrs->mosiPin != SPICC32XXDMA_PIN_NO_CONFIG) {
487         padRegister = (PinToPadGet((hwAttrs->mosiPin) & 0xff)<<2)
488             + PAD_CONFIG_BASE;
489         HWREG(padRegister) = PAD_RESET_STATE;
490     }
491     if (hwAttrs->misoPin != SPICC32XXDMA_PIN_NO_CONFIG) {
492         padRegister = (PinToPadGet((hwAttrs->misoPin) & 0xff)<<2)
493             + PAD_CONFIG_BASE;
494         HWREG(padRegister) = PAD_RESET_STATE;
495     }
496     if (hwAttrs->clkPin != SPICC32XXDMA_PIN_NO_CONFIG) {
497         padRegister = (PinToPadGet((hwAttrs->clkPin) & 0xff)<<2)
498             + PAD_CONFIG_BASE;
499         HWREG(padRegister) = PAD_RESET_STATE;
500     }
501     if ((hwAttrs->pinMode == SPI_4PIN_MODE) &&
502         (hwAttrs->csPin != SPICC32XXDMA_PIN_NO_CONFIG)) {
503         padRegister = (PinToPadGet((hwAttrs->csPin) & 0xff)<<2)
504             + PAD_CONFIG_BASE;
505         HWREG(padRegister) = PAD_RESET_STATE;
506     }
507 
508     object->isOpen = false;
509 }
510 
511 /*
512  *  ======== SPICC32XXDMA_control ========
513  */
SPICC32XXDMA_control(SPI_Handle handle,uint_fast16_t cmd,void * arg)514 int_fast16_t SPICC32XXDMA_control(SPI_Handle handle, uint_fast16_t cmd, void *arg)
515 {
516     return (SPI_STATUS_UNDEFINEDCMD);
517 }
518 
519 /*
520  *  ======== SPICC32XXDMA_init ========
521  */
SPICC32XXDMA_init(SPI_Handle handle)522 void SPICC32XXDMA_init(SPI_Handle handle)
523 {
524     UDMACC32XX_init();
525 }
526 
527 /*
528  *  ======== SPICC32XXDMA_open ========
529  */
SPICC32XXDMA_open(SPI_Handle handle,SPI_Params * params)530 SPI_Handle SPICC32XXDMA_open(SPI_Handle handle, SPI_Params *params)
531 {
532     uintptr_t                     key;
533     uint16_t                      pin;
534     uint16_t                      mode;
535     uint8_t                       powerMgrId;
536     HwiP_Params                   hwiParams;
537     SPICC32XXDMA_Object          *object = handle->object;
538     SPICC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
539 
540     key = HwiP_disable();
541 
542     if (object->isOpen) {
543         HwiP_restore(key);
544 
545         return (NULL);
546     }
547     object->isOpen = true;
548 
549     HwiP_restore(key);
550 
551     /* SPI_TI & SPI_MW are not supported */
552     if (params->frameFormat == SPI_TI || params->frameFormat == SPI_MW) {
553         object->isOpen = false;
554 
555         return (NULL);
556     }
557 
558     /* Register power dependency - i.e. power up and enable clock for SPI. */
559     powerMgrId = getPowerMgrId(hwAttrs->baseAddr);
560     if (powerMgrId > PowerCC32XX_NUMRESOURCES) {
561         object->isOpen = false;
562 
563         return (NULL);
564     }
565     Power_setDependency(powerMgrId);
566     Power_registerNotify(&(object->notifyObj), PowerCC32XX_AWAKE_LPDS,
567         postNotifyFxn, (uintptr_t) handle);
568 
569     /* Configure the pins */
570     if (hwAttrs->mosiPin != SPICC32XXDMA_PIN_NO_CONFIG) {
571         pin = (hwAttrs->mosiPin) & 0xff;
572         mode = (hwAttrs->mosiPin >> 8) & 0xff;
573         MAP_PinTypeSPI((unsigned long) pin, (unsigned long) mode);
574     }
575 
576     if (hwAttrs->misoPin != SPICC32XXDMA_PIN_NO_CONFIG) {
577         pin = (hwAttrs->misoPin) & 0xff;
578         mode = (hwAttrs->misoPin >> 8) & 0xff;
579         MAP_PinTypeSPI((unsigned long) pin, (unsigned long) mode);
580     }
581 
582     if (hwAttrs->clkPin != SPICC32XXDMA_PIN_NO_CONFIG) {
583         pin = (hwAttrs->clkPin) & 0xff;
584         mode = (hwAttrs->clkPin >> 8) & 0xff;
585         MAP_PinTypeSPI((unsigned long) pin, (unsigned long) mode);
586     }
587 
588     if (hwAttrs->pinMode == SPI_4PIN_MODE) {
589         if (hwAttrs->csPin != SPICC32XXDMA_PIN_NO_CONFIG) {
590             pin = (hwAttrs->csPin) & 0xff;
591             mode = (hwAttrs->csPin >> 8) & 0xff;
592             MAP_PinTypeSPI((unsigned long) pin, (unsigned long) mode);
593         }
594     }
595 
596     object->dmaHandle = UDMACC32XX_open();
597     if (object->dmaHandle == NULL) {
598         SPICC32XXDMA_close(handle);
599 
600         return (NULL);
601     }
602 
603     HwiP_Params_init(&hwiParams);
604     hwiParams.arg = (uintptr_t) handle;
605     hwiParams.priority = hwAttrs->intPriority;
606     object->hwiHandle = HwiP_create(hwAttrs->intNum, spiHwiFxn, &hwiParams);
607     if (object->hwiHandle == NULL) {
608         SPICC32XXDMA_close(handle);
609 
610         return (NULL);
611     }
612 
613     if (params->transferMode == SPI_MODE_BLOCKING) {
614         /*
615          * Create a semaphore to block task execution for the duration of the
616          * SPI transfer
617          */
618         object->transferComplete = SemaphoreP_createBinary(0);
619         if (object->transferComplete == NULL) {
620             SPICC32XXDMA_close(handle);
621 
622             return (NULL);
623         }
624 
625         object->transferCallbackFxn = blockingTransferCallback;
626     }
627     else {
628         if (params->transferCallbackFxn == NULL) {
629             SPICC32XXDMA_close(handle);
630 
631             return (NULL);
632         }
633 
634         object->transferCallbackFxn = params->transferCallbackFxn;
635     }
636 
637     object->bitRate = params->bitRate;
638     object->dataSize = params->dataSize;
639     object->frameFormat = params->frameFormat;
640     object->spiMode = params->mode;
641     object->transaction = NULL;
642     object->transferMode = params->transferMode;
643     object->transferTimeout = params->transferTimeout;
644 
645     /* SPI FIFO trigger sizes vary based on data frame size */
646     if (object->dataSize < 9) {
647         object->rxFifoTrigger = sizeof(uint8_t);
648         object->txFifoTrigger = sizeof(uint8_t);
649     }
650     else if (object->dataSize < 17) {
651         object->rxFifoTrigger = sizeof(uint16_t);
652         object->txFifoTrigger = sizeof(uint16_t);
653     }
654     else {
655         object->rxFifoTrigger = sizeof(uint32_t);
656         object->txFifoTrigger = sizeof(uint32_t);
657     }
658 
659     initHw(object, hwAttrs);
660 
661     return (handle);
662 }
663 
664 /*
665  *  ======== SPICC32XXDMA_transfer ========
666  */
SPICC32XXDMA_transfer(SPI_Handle handle,SPI_Transaction * transaction)667 bool SPICC32XXDMA_transfer(SPI_Handle handle, SPI_Transaction *transaction)
668 {
669     uintptr_t                     key;
670     uint8_t                       alignMask;
671     bool                          buffersAligned;
672     SPICC32XXDMA_Object          *object = handle->object;
673     SPICC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
674 
675     if ((transaction->count == 0) ||
676         (transaction->rxBuf == NULL && transaction->txBuf == NULL) ||
677         (hwAttrs->scratchBufPtr == NULL && (transaction->rxBuf == NULL ||
678             transaction->txBuf == NULL))) {
679         return (false);
680     }
681 
682     key = HwiP_disable();
683 
684     /*
685      * alignMask is used to determine if the RX/TX buffers addresses are
686      * aligned to the data frame size.
687      */
688     alignMask = (object->rxFifoTrigger - 1);
689     buffersAligned = ((((uint32_t) transaction->rxBuf & alignMask) == 0) &&
690         (((uint32_t) transaction->txBuf & alignMask) == 0));
691 
692     if (object->transaction) {
693         HwiP_restore(key);
694 
695         return (false);
696     }
697     else {
698         object->transaction = transaction;
699         object->transaction->status = SPI_TRANSFER_STARTED;
700         object->amtDataXferred = 0;
701         object->currentXferAmt = 0;
702     }
703 
704     HwiP_restore(key);
705 
706     /* Set constraints to guarantee transaction */
707     Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
708 
709     /* Polling transfer if BLOCKING mode & transaction->count < threshold */
710     if ((object->transferMode == SPI_MODE_BLOCKING &&
711         transaction->count < hwAttrs->minDmaTransferSize) || !buffersAligned) {
712         spiPollingTransfer(object, hwAttrs, transaction);
713 
714         /* Transaction completed; set status & mark SPI ready */
715         object->transaction->status = SPI_TRANSFER_COMPLETED;
716         object->transaction = NULL;
717 
718         Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
719     }
720     else {
721         /* Perform a DMA backed SPI transfer */
722         configDMA(object, hwAttrs, transaction);
723 
724         if (object->transferMode == SPI_MODE_BLOCKING) {
725             if (SemaphoreP_pend(object->transferComplete,
726                 object->transferTimeout) != SemaphoreP_OK) {
727                 /* Timeout occurred; cancel the transfer */
728                 object->transaction->status = SPI_TRANSFER_FAILED;
729                 SPICC32XXDMA_transferCancel(handle);
730 
731                 /*
732                  * TransferCancel() performs callback which posts
733                  * transferComplete semaphore. This call consumes this extra post.
734                  */
735                 SemaphoreP_pend(object->transferComplete, SemaphoreP_NO_WAIT);
736 
737                 return (false);
738             }
739         }
740     }
741 
742     return (true);
743 }
744 
745 /*
746  *  ======== SPICC32XXDMA_transferCancel ========
747  */
SPICC32XXDMA_transferCancel(SPI_Handle handle)748 void SPICC32XXDMA_transferCancel(SPI_Handle handle)
749 {
750     uintptr_t                     key;
751     SPI_Transaction              *msg;
752     SPICC32XXDMA_Object          *object = handle->object;
753     SPICC32XXDMA_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
754 
755     /*
756      * There are 2 use cases in which to call transferCancel():
757      *   1.  The driver is in CALLBACK mode.
758      *   2.  The driver is in BLOCKING mode & there has been a transfer timeout.
759      */
760     if (object->transferMode == SPI_MODE_CALLBACK ||
761         object->transaction->status == SPI_TRANSFER_FAILED) {
762 
763         key = HwiP_disable();
764 
765         if (object->transaction == NULL || object->cancelInProgress) {
766             HwiP_restore(key);
767 
768             return;
769         }
770         object->cancelInProgress = true;
771 
772         /* Prevent interrupt from occurring while canceling the transfer */
773         HwiP_disableInterrupt(hwAttrs->intNum);
774         HwiP_clearInterrupt(hwAttrs->intNum);
775 
776         /* Clear DMA configuration */
777         MAP_uDMAChannelDisable(hwAttrs->rxChannelIndex);
778         MAP_uDMAChannelDisable(hwAttrs->txChannelIndex);
779 
780         MAP_SPIIntDisable(hwAttrs->baseAddr, SPI_INT_DMARX);
781         MAP_SPIIntClear(hwAttrs->baseAddr, SPI_INT_DMARX);
782         MAP_SPIDmaDisable(hwAttrs->baseAddr, SPI_RX_DMA | SPI_TX_DMA);
783 
784         HwiP_restore(key);
785 
786         /*
787          * Disables peripheral, clears all registers & reinitializes it to
788          * parameters used in SPI_open()
789          */
790         initHw(object, hwAttrs);
791 
792         HwiP_enableInterrupt(hwAttrs->intNum);
793 
794         /*
795          * Calculate amount of data which has already been sent & store
796          * it in transaction->count
797          */
798         object->transaction->count = object->amtDataXferred +
799             (object->currentXferAmt - getDmaRemainingXfers(hwAttrs));
800 
801         /* Set status CANCELED if we did not cancel due to timeout  */
802         if (object->transaction->status == SPI_TRANSFER_STARTED) {
803             object->transaction->status = SPI_TRANSFER_CANCELED;
804         }
805 
806         /* Release constraint set during transaction */
807         Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
808 
809         /*
810          * Use a temporary transaction pointer in case the callback function
811          * attempts to perform another SPI_transfer call
812          */
813         msg = object->transaction;
814 
815         /* Indicate we are done with this transfer */
816         object->transaction = NULL;
817         object->cancelInProgress = false;
818         object->transferCallbackFxn(handle, msg);
819     }
820 }
821