1 //*****************************************************************************
2 //
3 //! @file am_hal_iom.c
4 //!
5 //! @brief Functions for Interfacing with IO Master Serial (SPI/I2C) Modules.
6 //!
7 //! @addtogroup iom3p IOM - IOM (MASTER SPI/I2C) Functions
8 //! @ingroup apollo3p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 #ifdef __IAR_SYSTEMS_ICC__
53 #define AM_INSTR_CLZ(n)                     __CLZ(n)
54 #else
55 #define AM_INSTR_CLZ(n)                     __builtin_clz(n)
56 #endif
57 
58 #define MANUAL_POP  0
59 
60 #define AM_HAL_MAGIC_IOM            0x123456
61 #define AM_HAL_IOM_CHK_HANDLE(h)    ((h) && ((am_hal_handle_prefix_t *)(h))->s.bInit && (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_IOM))
62 
63 // For IOM - Need to clear the flag for unpausing
64 #define AM_HAL_IOM_SC_PAUSE_CQ         AM_HAL_IOM_SC_PAUSE(AM_HAL_IOM_PAUSE_FLAG_CQ)
65 #define AM_HAL_IOM_SC_PAUSE_SEQLOOP    AM_HAL_IOM_SC_PAUSE(AM_HAL_IOM_PAUSE_FLAG_SEQLOOP)
66 #define AM_HAL_IOM_SC_UNPAUSE_CQ       AM_HAL_IOM_SC_UNPAUSE(AM_HAL_IOM_PAUSE_FLAG_CQ)
67 #define AM_HAL_IOM_SC_UNPAUSE_SEQLOOP  AM_HAL_IOM_SC_UNPAUSE(AM_HAL_IOM_PAUSE_FLAG_SEQLOOP)
68 #define AM_HAL_IOM_SC_PAUSE_BLOCK      AM_HAL_IOM_SC_PAUSE(AM_HAL_IOM_PAUSE_FLAG_BLOCK)
69 #define AM_HAL_IOM_SC_UNPAUSE_BLOCK    AM_HAL_IOM_SC_UNPAUSE(AM_HAL_IOM_PAUSE_FLAG_BLOCK)
70 
71 // Max time to wait when attempting to pause the command queue
72 #define AM_HAL_IOM_MAX_PAUSE_DELAY     (100*1000) // 100ms
73 
74 //*****************************************************************************
75 //
76 // IOM interface clock selections
77 //
78 //*****************************************************************************
79 #define AM_REG_IOM_CLKCFG_FSEL_MIN_PWR               0x00000000
80 #define AM_REG_IOM_CLKCFG_FSEL_HFRC                  0x00000100
81 #define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV2             0x00000200
82 #define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV4             0x00000300
83 #define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV8             0x00000400
84 #define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV16            0x00000500
85 #define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV32            0x00000600
86 #define AM_REG_IOM_CLKCFG_FSEL_HFRC_DIV64            0x00000700
87 
88 //
89 // Only keep IOM interrupts we're interested in
90 //
91 // Necessary interrupts for respective modes
92 // For CQ - we rely only on the CQUPD interrupt
93 #define AM_HAL_IOM_INT_CQMODE   (AM_HAL_IOM_INT_CQUPD | AM_HAL_IOM_INT_ERR)
94 // Need both CMDCMP & DCMP, as for Read we need to wait for DCMP after CMDCMP
95 #define AM_HAL_IOM_INT_DMAMODE  (AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_ERR)
96 
97 // Configures the interrupts to provided coniguration - clearing all pending interrupts
98 #define IOM_SET_INTEN(ui32Module, intCfg)                               \
99     do                                                                  \
100     {                                                                   \
101         IOMn(ui32Module)->INTEN = 0;                                    \
102         IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;                  \
103         IOMn(ui32Module)->INTEN = (intCfg);                             \
104     } while (0);
105 
106 
107 //*****************************************************************************
108 //
109 // Private Types.
110 //
111 //*****************************************************************************
112 
113 //
114 // Command Queue entry structure.
115 //
116 typedef struct
117 {
118     uint32_t    ui32PAUSENAddr;
119     uint32_t    ui32PAUSEENVal;
120     uint32_t    ui32PAUSEN2Addr;
121     uint32_t    ui32PAUSEEN2Val;
122     uint32_t    ui32OFFSETHIAddr;
123     uint32_t    ui32OFFSETHIVal;
124     uint32_t    ui32DEVCFGAddr;
125     uint32_t    ui32DEVCFGVal;
126     uint32_t    ui32DMACFGdis1Addr;
127     uint32_t    ui32DMACFGdis1Val;
128     uint32_t    ui32DMATOTCOUNTAddr;
129     uint32_t    ui32DMATOTCOUNTVal;
130     uint32_t    ui32DMATARGADDRAddr;
131     uint32_t    ui32DMATARGADDRVal;
132     uint32_t    ui32DMACFGAddr;
133     uint32_t    ui32DMACFGVal;
134     uint32_t    ui32DCXAddr;
135     uint32_t    ui32DCXVal;
136     uint32_t    ui32CMDAddr;
137     uint32_t    ui32CMDVal;
138     uint32_t    ui32SETCLRAddr;
139     uint32_t    ui32SETCLRVal;
140 } am_hal_iom_txn_cmdlist_t;
141 
142 //
143 // Command Queue entry structure for Sequence Repeat
144 //
145 typedef struct
146 {
147     uint32_t                    ui32PAUSENAddr;
148     uint32_t                    ui32PAUSEENVal;
149     uint32_t                    ui32PAUSEN2Addr;
150     uint32_t                    ui32PAUSEEN2Val;
151     uint32_t                    ui32SETCLRAddr;
152     uint32_t                    ui32SETCLRVal;
153 } am_hal_iom_cq_loop_entry_t;
154 
155 #define AM_HAL_IOM_MAX_PENDING_TRANSACTIONS      256 // Must be power of 2 for the implementation below
156 #define AM_HAL_IOM_CQUPD_INT_FLAG                (0x00000001)
157 
158 typedef struct
159 {
160     bool        bValid;
161     uint32_t    regFIFOTHR;
162     uint32_t    regDMATRIGEN;
163     uint32_t    regCLKCFG;
164     uint32_t    regSUBMODCTRL;
165     uint32_t    regCQCFG;
166     uint32_t    regCQADDR;
167     uint32_t    regCQFLAGS;
168     uint32_t    regCQPAUSEEN;
169     uint32_t    regCQCURIDX;
170     uint32_t    regCQENDIDX;
171     uint32_t    regMSPICFG;
172     uint32_t    regMI2CCFG;
173     uint32_t    regINTEN;
174 } am_hal_iom_register_state_t;
175 
176 typedef enum
177 {
178     AM_HAL_IOM_SEQ_NONE,
179     AM_HAL_IOM_SEQ_UNDER_CONSTRUCTION,
180     AM_HAL_IOM_SEQ_RUNNING,
181 } am_hal_iom_seq_e;
182 
183 typedef struct
184 {
185     uint32_t                    ui32OFFSETHIVal;
186     uint32_t                    ui32DEVCFGVal;
187     uint32_t                    ui32DMATOTCOUNTVal;
188     uint32_t                    ui32DMATARGADDRVal;
189     uint32_t                    ui32DMACFGVal;
190     uint32_t                    ui32CMDVal;
191     am_hal_iom_callback_t       pfnCallback;
192     void                        *pCallbackCtxt;
193 } am_hal_iom_dma_entry_t;
194 
195 typedef struct
196 {
197     am_hal_handle_prefix_t  prefix;
198     //
199     // Physical module number.
200     //
201     uint32_t                ui32Module;
202 
203     //
204     // Interface mode (SPI or I2C).
205     //
206     am_hal_iom_mode_e       eInterfaceMode;
207 
208     //
209     // Non-Blocking transaction Tranfer Control Buffer.
210     //
211     uint32_t                *pNBTxnBuf;
212     uint32_t                ui32NBTxnBufLength;
213 
214     //
215     // Saves the user application defined interrupt configuration.
216     //
217     uint32_t                ui32UserIntCfg;
218 
219     //
220     // Saves the transaction interrupt state for non-blocking interrupt service.
221     //
222     uint32_t                ui32TxnInt;
223 
224     //
225     // Index of last non-blocking transaction processed in CQ.
226     //
227     uint32_t                ui32LastIdxProcessed;
228 
229     // Maximum number of transactions allowed in the CQ.
230     uint32_t                ui32MaxTransactions;
231 
232     //
233     // Number of pending transactions in the CQ.
234     //
235     volatile uint32_t       ui32NumPendTransactions;
236 
237     //
238     // Stores the CQ callbacks and contexts.
239     //
240     am_hal_iom_callback_t   pfnCallback[AM_HAL_IOM_MAX_PENDING_TRANSACTIONS];
241     void                    *pCallbackCtxt[AM_HAL_IOM_MAX_PENDING_TRANSACTIONS];
242 
243     //
244     // Handle to the CQ.
245     //
246     void                    *pCmdQHdl;
247 
248     //
249     // To support sequence.
250     //
251     am_hal_iom_seq_e        eSeq;
252     bool                    bAutonomous;
253 
254     //
255     // This is used to track the number of transactions in a sequence.
256     //
257     uint32_t                ui32NumSeqTransactions;
258     volatile bool           bRestart;
259     uint32_t                block;
260 
261     //
262     // To support high priority transactions - out of band
263     // High Priority DMA transactions
264     //
265     volatile bool           bHP;
266     uint32_t                ui32NumHPEntries;
267     uint32_t                ui32NumHPPendingEntries;
268     uint32_t                ui32MaxHPTransactions;
269     uint32_t                ui32NextHPIdx;
270     uint32_t                ui32LastHPIdxProcessed;
271     am_hal_iom_dma_entry_t  *pHPTransactions;
272     // Max pending transactions based on NB Buffer size
273     uint32_t                ui32MaxPending;
274     // Number of back to back transactions with no callbacks
275     uint32_t                ui32NumUnSolicited;
276     //
277     // Delay timeout value.
278     //
279     uint32_t                waitTimeout;
280 
281     //
282     // Configured clock time.
283     //
284     uint32_t                ui32BitTimeTicks;
285 
286     //
287     // IOM register state for power down save/restore.
288     //
289     am_hal_iom_register_state_t registerState;
290     uint8_t                 dcx[AM_HAL_IOM_MAX_CS_SPI + 1];
291 
292 } am_hal_iom_state_t;
293 
294 //*****************************************************************************
295 //
296 // Globals
297 //
298 //*****************************************************************************
299 am_hal_iom_state_t          g_IOMhandles[AM_REG_IOM_NUM_MODULES];
300 
301 //*****************************************************************************
302 //
303 // Internal Functions.
304 //
305 //*****************************************************************************
306 
307 //*****************************************************************************
308 //! @brief Get the pause val object
309 //!
310 //! @param pIOMState
311 //! @param pause
312 //! @return uint32_t
313 //*****************************************************************************
314 static uint32_t
get_pause_val(am_hal_iom_state_t * pIOMState,uint32_t pause)315 get_pause_val(am_hal_iom_state_t *pIOMState, uint32_t pause)
316 {
317     uint32_t retval;
318     switch (pIOMState->block)
319     {
320         case 1:
321             // Pause the CQ till the whole block is built
322             retval = pause | AM_HAL_IOM_CQP_PAUSE_DEFAULT | AM_HAL_IOM_PAUSE_FLAG_BLOCK;
323             pIOMState->block = 2;
324             break;
325         case 2:
326             // No pausing allowed
327             retval = AM_HAL_IOM_PAUSE_DEFAULT;
328             break;
329         default: // case 0
330             retval = pause | AM_HAL_IOM_CQP_PAUSE_DEFAULT;
331     }
332     return retval;
333 }
334 
335 //*****************************************************************************
336 //! @brief  Function to build the CMD value.
337 //!
338 //! @note Returns the CMD value, but does not set the CMD register.
339 //!
340 //! @note The OFFSETHI register must still be handled by the caller, e.g.
341 //!       AM_REGn(IOM, ui32Module, OFFSETHI) = (uint16_t)(ui32Offset >> 8);
342 //!
343 //! @param ui32CS
344 //! @param ui32Dir
345 //! @param ui32Cont
346 //! @param ui32Offset
347 //! @param ui32OffsetCnt
348 //! @param ui32nBytes
349 //! @return uint32_t CMD value
350 //*****************************************************************************
351 static uint32_t
build_cmd(uint32_t ui32CS,uint32_t ui32Dir,uint32_t ui32Cont,uint32_t ui32Offset,uint32_t ui32OffsetCnt,uint32_t ui32nBytes)352 build_cmd(uint32_t ui32CS,     uint32_t ui32Dir, uint32_t ui32Cont,
353           uint32_t ui32Offset, uint32_t ui32OffsetCnt,
354           uint32_t ui32nBytes)
355 {
356     //
357     // Initialize the CMD variable
358     //
359     uint32_t ui32Cmd = 0;
360 
361     //
362     // If SPI, we'll need the chip select
363     //
364     ui32Cmd |= _VAL2FLD(IOM0_CMD_CMDSEL, ui32CS);
365 
366     //
367     // Build the CMD with number of bytes and direction.
368     //
369     ui32Cmd |= _VAL2FLD(IOM0_CMD_TSIZE, ui32nBytes);
370 
371     if (ui32Dir == AM_HAL_IOM_RX)
372     {
373         ui32Cmd |= _VAL2FLD(IOM0_CMD_CMD, IOM0_CMD_CMD_READ);
374     }
375     else
376     {
377         ui32Cmd |= _VAL2FLD(IOM0_CMD_CMD, IOM0_CMD_CMD_WRITE);
378     }
379 
380     ui32Cmd |= _VAL2FLD(IOM0_CMD_CONT, ui32Cont);
381 
382     //
383     // Now add the OFFSETLO and OFFSETCNT information.
384     //
385     ui32Cmd |= _VAL2FLD(IOM0_CMD_OFFSETLO, (uint8_t)ui32Offset);
386     ui32Cmd |= _VAL2FLD(IOM0_CMD_OFFSETCNT, ui32OffsetCnt);
387 
388     return ui32Cmd;
389 } // build_cmd()
390 
391 //*****************************************************************************
392 //
393 //! @brief Function to build CMD lists.
394 //!
395 //! @param pIOMState
396 //! @param pCQEntry
397 //! @param psTransaction
398 //
399 //*****************************************************************************
400 static void
build_txn_cmdlist(am_hal_iom_state_t * pIOMState,am_hal_iom_txn_cmdlist_t * pCQEntry,am_hal_iom_transfer_t * psTransaction)401 build_txn_cmdlist(am_hal_iom_state_t       *pIOMState,
402                   am_hal_iom_txn_cmdlist_t *pCQEntry,
403                   am_hal_iom_transfer_t    *psTransaction)
404 {
405     uint32_t                ui32Cmd;
406     uint32_t                ui32Module = pIOMState->ui32Module;
407     uint32_t                ui32Dir = psTransaction->eDirection;
408     uint32_t                ui32DMAAddress;
409 
410     //
411     // Command for OFFSETHI
412     //
413     pCQEntry->ui32OFFSETHIAddr  = (uint32_t)&IOMn(ui32Module)->OFFSETHI;
414 
415     pCQEntry->ui32OFFSETHIVal   = (uint16_t)(psTransaction->ui32Instr >> 8);
416 
417     //
418     // Command for I2C DEVADDR field in DEVCFG
419     //
420     pCQEntry->ui32DEVCFGAddr    = (uint32_t)&IOMn(ui32Module)->DEVCFG;
421     pCQEntry->ui32DEVCFGVal     = _VAL2FLD(IOM0_DEVCFG_DEVADDR, psTransaction->uPeerInfo.ui32I2CDevAddr);
422 
423     //
424     // Command to disable DMA before writing TOTCOUNT.
425     //
426     pCQEntry->ui32DMACFGdis1Addr   = (uint32_t)&IOMn(ui32Module)->DMACFG;
427     pCQEntry->ui32DMACFGdis1Val    = 0x0;
428 
429     //
430     // Command to set DMATOTALCOUNT
431     //
432     pCQEntry->ui32DMATOTCOUNTAddr = (uint32_t)&IOMn(ui32Module)->DMATOTCOUNT;
433     pCQEntry->ui32DMATOTCOUNTVal  = psTransaction->ui32NumBytes;
434 
435     //
436     // Command to set DMATARGADDR
437     //
438     pCQEntry->ui32DMATARGADDRAddr = (uint32_t)&IOMn(ui32Module)->DMATARGADDR;
439     ui32DMAAddress = (ui32Dir == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
440     pCQEntry->ui32DMATARGADDRVal  = ui32DMAAddress;
441 
442     //
443     // Command to set DMACFG to start the DMA operation
444     //
445     pCQEntry->ui32DMACFGAddr    = (uint32_t)&IOMn(ui32Module)->DMACFG;
446     pCQEntry->ui32DMACFGVal     =
447         _VAL2FLD(IOM0_DMACFG_DMAPRI, psTransaction->ui8Priority)     |
448         _VAL2FLD(IOM0_DMACFG_DMADIR, ui32Dir == AM_HAL_IOM_TX ? 1 : 0);
449 
450     if (psTransaction->ui32NumBytes)
451     {
452         pCQEntry->ui32DMACFGVal |= IOM0_DMACFG_DMAEN_Msk;
453     }
454 
455     // CMDRPT register has been repurposed for DCX
456     pCQEntry->ui32DCXAddr = (uint32_t)&IOMn(ui32Module)->DCX;
457     pCQEntry->ui32DCXVal = (pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE)  ? pIOMState->dcx[psTransaction->uPeerInfo.ui32SpiChipSelect] : 0;
458     //
459     // Command to start the transfer.
460     //
461     ui32Cmd = pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE  ?
462               psTransaction->uPeerInfo.ui32SpiChipSelect : 0;
463     ui32Cmd = build_cmd(ui32Cmd,                            // ChipSelect
464                         ui32Dir,          // ui32Dir
465                         psTransaction->bContinue,           // ui32Cont
466                         psTransaction->ui32Instr,           // ui32Offset
467                         psTransaction->ui32InstrLen,        // ui32OffsetCnt
468                         psTransaction->ui32NumBytes);  // ui32Bytes
469 
470     pCQEntry->ui32CMDAddr  = (uint32_t)&IOMn(ui32Module)->CMD;
471     pCQEntry->ui32CMDVal   = ui32Cmd;
472 
473     pCQEntry->ui32PAUSENAddr = pCQEntry->ui32PAUSEN2Addr = (uint32_t)&IOMn(ui32Module)->CQPAUSEEN;
474     pCQEntry->ui32PAUSEEN2Val = AM_HAL_IOM_PAUSE_DEFAULT;
475     pCQEntry->ui32PAUSEENVal = get_pause_val(pIOMState, psTransaction->ui32PauseCondition);
476     pCQEntry->ui32SETCLRVal = psTransaction->ui32StatusSetClr;
477     pCQEntry->ui32SETCLRAddr = (uint32_t)&IOMn(ui32Module)->CQSETCLEAR;
478 
479 } // build_txn_cmdlist()
480 
481 //*****************************************************************************
482 //
483 //! @brief Utilizes the built-in fields that indicate whether which
484 //!                      submodule is supported, then enables that submodule.
485 //!
486 //! @param ui32Module    IOM module
487 //! @param ui32Type      = 0, set for SPI; =1, set for I2C.
488 //
489 //*****************************************************************************
490 static void
enable_submodule(uint32_t ui32Module,uint32_t ui32Type)491 enable_submodule(uint32_t ui32Module, uint32_t ui32Type)
492 {
493     if ( IOMn(ui32Module)->SUBMODCTRL_b.SMOD0TYPE == ui32Type )
494     {
495         IOMn(ui32Module)->SUBMODCTRL =
496              _VAL2FLD(IOM0_SUBMODCTRL_SMOD1EN, 0) |
497              _VAL2FLD(IOM0_SUBMODCTRL_SMOD0EN, 1);
498     }
499     else
500     {
501         IOMn(ui32Module)->SUBMODCTRL =
502              _VAL2FLD(IOM0_SUBMODCTRL_SMOD1EN, 1) |
503              _VAL2FLD(IOM0_SUBMODCTRL_SMOD0EN, 0);
504     }
505 } // enable_submodule()
506 
507 //*****************************************************************************
508 // @brief Error handling.
509 //
510 // @param ui32Module
511 // @param ui32IntStatus
512 // @return uint32_t   Status
513 //*****************************************************************************
514 uint32_t
internal_iom_get_int_err(uint32_t ui32Module,uint32_t ui32IntStatus)515 internal_iom_get_int_err(uint32_t ui32Module, uint32_t ui32IntStatus)
516 {
517     //
518     // Map the INTSTAT bits for transaction status
519     //
520     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
521 
522     //
523     // Let's accumulate the errors
524     //
525     ui32IntStatus |= IOMn(ui32Module)->INTSTAT;
526 
527     if (ui32IntStatus & AM_HAL_IOM_INT_SWERR)
528     {
529         // Error in hardware command issued or illegal access by SW
530         ui32Status = AM_HAL_IOM_ERR_INVALID_OPER;
531     }
532     else if (ui32IntStatus & AM_HAL_IOM_INT_I2CARBERR)
533     {
534         // Loss of I2C multi-master arbitration
535         ui32Status = AM_HAL_IOM_ERR_I2C_ARB;
536     }
537     else if (ui32IntStatus & AM_HAL_IOM_INT_NAK)
538     {
539         // I2C NAK
540         ui32Status = AM_HAL_IOM_ERR_I2C_NAK;
541     }
542     else if (ui32IntStatus & AM_HAL_IOM_INT_INTERR)
543     {
544         // Other Error
545         ui32Status = AM_HAL_STATUS_FAIL;
546     }
547 
548     return ui32Status;
549 
550 } // internal_iom_get_int_err()
551 
552 //*****************************************************************************
553 //! @brief
554 //!
555 //! @param pIOMState
556 //! @param ui32IntMask
557 //*****************************************************************************
558 static void
internal_iom_reset_on_error(am_hal_iom_state_t * pIOMState,uint32_t ui32IntMask)559 internal_iom_reset_on_error(am_hal_iom_state_t  *pIOMState, uint32_t ui32IntMask)
560 {
561     uint32_t iterationsToWait = 2 * pIOMState->ui32BitTimeTicks; // effectively > 6 clocks
562     uint32_t ui32Module = pIOMState->ui32Module;
563     uint32_t curIntCfg = IOMn(ui32Module)->INTEN;
564     IOMn(ui32Module)->INTEN = 0;
565 
566     // Disable interrupts temporarily
567     if (ui32IntMask & AM_HAL_IOM_INT_DERR)
568     {
569         if ((IOMn(ui32Module)->DMACFG & IOM0_DMACFG_DMADIR_Msk) == _VAL2FLD(IOM0_DMACFG_DMADIR, IOM0_DMACFG_DMADIR_M2P))
570         {
571             // Write
572             uint32_t dummy = 0xDEADBEEF;
573             uint32_t numBytesRemaining = IOMn(ui32Module)->DMATOTCOUNT;
574 
575             while (numBytesRemaining)
576             {
577                 if (IOMn(ui32Module)->FIFOPTR_b.FIFO0REM >= 4)
578                 {
579                     // Write one 4-byte word to FIFO
580                     IOMn(ui32Module)->FIFOPUSH = dummy;
581                     if (numBytesRemaining > 4)
582                     {
583                         numBytesRemaining -= 4;
584                     }
585                     else
586                     {
587                         break;
588                     }
589                 }
590             }
591             // Now wait for command to finish
592             while ((IOMn(ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk);
593         }
594         else
595         {
596             // Read
597             // Let command finish
598             while (IOMn(ui32Module)->STATUS_b.CMDACT)
599             {
600                 while (IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ >= 4)
601                 {
602                     // Read one 4-byte word from FIFO
603                     IOMn(ui32Module)->FIFOPOP;
604 #if MANUAL_POP
605                     IOMn(ui32Module)->FIFOPOP = 0x11111111;
606 #endif
607                 }
608             }
609             // Now wait for command to finish
610             while ((IOMn(ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk);
611             // Flush any remaining data from FIFO
612             while  (IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ)
613             {
614                 while (IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ >= 4)
615                 {
616                     // Read one 4-byte word from FIFO
617                     IOMn(ui32Module)->FIFOPOP;
618 #if MANUAL_POP
619                     IOMn(ui32Module)->FIFOPOP = 0x11111111;
620 #endif
621                 }
622             }
623         }
624     }
625     if (ui32IntMask & (AM_HAL_IOM_INT_NAK | AM_HAL_IOM_INT_ARB))
626     {
627         uint32_t iomDbg = IOMn(ui32Module)->IOMDBG;
628         //
629         // Wait for Idle
630         //
631         while ((IOMn(ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk);
632 
633         //
634         // Reset Submodule & FIFO
635         //
636         // Disable the submodules
637         //
638         IOMn(ui32Module)->SUBMODCTRL_b.SMOD1EN = 0;
639         // Reset Fifo
640         IOMn(ui32Module)->FIFOCTRL_b.FIFORSTN = 0;
641 
642         // Disable Clock gating
643         IOMn(ui32Module)->IOMDBG |= IOM0_IOMDBG_IOCLKON_Msk;
644         // Wait for few IO clock cycles
645         am_hal_flash_delay(iterationsToWait);
646         // Revert
647         IOMn(ui32Module)->IOMDBG = iomDbg;
648 
649         IOMn(ui32Module)->FIFOCTRL_b.FIFORSTN = 1;
650 
651         // Enable submodule
652         IOMn(ui32Module)->SUBMODCTRL_b.SMOD1EN = 1;
653     }
654 
655     IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
656 
657     // Restore interrupts
658     IOMn(ui32Module)->INTEN = curIntCfg;
659 }
660 
661 //*****************************************************************************
662 //
663 //! @brief  Compute the interface frequency based on the given parameters
664 //!
665 //! @param ui32HFRCfreqHz
666 //! @param ui32Fsel
667 //! @param ui32Div3
668 //! @param ui32DivEn
669 //! @param ui32TotPer
670 //!
671 //! @return uint32_t
672 //
673 //*****************************************************************************
674 static uint32_t
compute_freq(uint32_t ui32HFRCfreqHz,uint32_t ui32Fsel,uint32_t ui32Div3,uint32_t ui32DivEn,uint32_t ui32TotPer)675 compute_freq(uint32_t ui32HFRCfreqHz,
676              uint32_t ui32Fsel, uint32_t ui32Div3,
677              uint32_t ui32DivEn, uint32_t ui32TotPer)
678 {
679     uint32_t ui32Denomfinal, ui32ClkFreq;
680 
681     ui32Denomfinal = ((1 << (ui32Fsel - 1)) * (1 + ui32Div3 * 2) * (1 + ui32DivEn * (ui32TotPer)));
682     ui32ClkFreq = (ui32HFRCfreqHz) / ui32Denomfinal;                           // Compute the set frequency value
683     ui32ClkFreq +=  (((ui32HFRCfreqHz) % ui32Denomfinal) > (ui32Denomfinal / 2)) ? 1 : 0;
684 
685     return ui32ClkFreq;
686 } // compute_freq()
687 
688 //*****************************************************************************
689 //
690 //! @brief A power of 2?
691 //! @details Return true if ui32Value has exactly 1 bit set, otherwise false.
692 //!
693 //! @param ui32Value
694 //!
695 //! @return true    if ui32Value has exactly 1 bit set
696 //! @return false   if ui32Value doesn't have exactly 1 bit set
697 //
698 //*****************************************************************************
699 static bool
onebit(uint32_t ui32Value)700 onebit(uint32_t ui32Value)
701 {
702     return ui32Value  &&  !(ui32Value & (ui32Value - 1));
703 } // onebit()
704 
705 //*****************************************************************************
706 //
707 //! @brief Returns the proper settings for the CLKCFG register
708 //!
709 //! @details Given a desired serial interface clock frequency, this function computes
710 //! the appropriate settings for the various fields in the CLKCFG register
711 //! and returns the 32-bit value that should be written to that register.
712 //! The actual interface frequency may be slightly lower than the specified
713 //! frequency, but the actual frequency is also returned.
714 //!
715 //! @note A couple of criteria that this algorithm follow are:
716 //!  1. For power savings, choose the highest FSEL possible.
717 //!  2. Use DIV3 when possible rather than DIVEN.
718 //!
719 //!
720 //! @note 0 (64 bits) = error. Note that the caller must check the entire 64 bits.
721 //! It is not an error if only the low 32-bits are 0 (this is a valid value).
722 //! But the entire 64 bits returning 0 is an error.
723 //!
724 //! @param ui32FreqHz - The desired interface frequency in Hz
725 //! @param ui32Phase
726 //!
727 //! @return uint64_t The lower 32-bits represent the value to use to set CLKCFG
728 //! @return uint64_t The upper 32-bits represent the actual frequency (in Hz) that will result
729 //! from setting CLKCFG with the lower 32-bits.
730 //
731 //*****************************************************************************
732 static
iom_get_interface_clock_cfg(uint32_t ui32FreqHz,uint32_t ui32Phase)733 uint64_t iom_get_interface_clock_cfg(uint32_t ui32FreqHz, uint32_t ui32Phase )
734 {
735     uint32_t ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer, ui32LowPer;
736     uint32_t ui32Denom, ui32v1, ui32Denomfinal, ui32ClkFreq, ui32ClkCfg;
737     uint32_t ui32HFRCfreqHz;
738     int32_t i32Div, i32N;
739 
740     if ( ui32FreqHz == 0 )
741     {
742         return 0;
743     }
744 
745     //
746     // Set the HFRC clock frequency.
747     //
748     ui32HFRCfreqHz = AM_HAL_CLKGEN_FREQ_MAX_HZ;
749 
750     //
751     // Compute various parameters used for computing the optimal CLKCFG setting.
752     //
753     i32Div = (ui32HFRCfreqHz / ui32FreqHz) + ((ui32HFRCfreqHz % ui32FreqHz) ? 1 : 0);    // Round up (ceiling)
754 
755     //
756     // Compute N (count the number of LS zeros of Div) = ctz(Div) = log2(Div & (-Div))
757     //
758     i32N = 31 - AM_INSTR_CLZ((i32Div & (-i32Div)));
759 
760     if ( i32N > 6 )
761     {
762         i32N = 6;
763     }
764 
765     ui32Div3 = ( (ui32FreqHz < (ui32HFRCfreqHz / 16384))            ||
766                  ( ((ui32FreqHz >= (ui32HFRCfreqHz / 3))    &&
767                     (ui32FreqHz <= ((ui32HFRCfreqHz / 2) - 1)) ) ) ) ? 1 : 0;
768     ui32Denom = ( 1 << i32N ) * ( 1 + (ui32Div3 * 2) );
769     ui32TotPer = i32Div / ui32Denom;
770     ui32TotPer += (i32Div % ui32Denom) ? 1 : 0;
771     ui32v1 = 31 - AM_INSTR_CLZ(ui32TotPer);     // v1 = log2(TotPer)
772     ui32Fsel = (ui32v1 > 7) ? ui32v1 + i32N - 7 : i32N;
773     ui32Fsel++;
774 
775     if ( ui32Fsel > 7 )
776     {
777         //
778         // This is an error, can't go that low.
779         //
780         return 0;
781     }
782 
783     if ( ui32v1 > 7 )
784     {
785         ui32DivEn = ui32TotPer;     // Save TotPer for the round up calculation
786         ui32TotPer = ui32TotPer>>(ui32v1-7);
787         ui32TotPer += ((ui32DivEn) % (1 << (ui32v1 - 7))) ? 1 : 0;
788     }
789 
790     ui32DivEn = ( (ui32FreqHz >= (ui32HFRCfreqHz / 4)) ||
791                   ((1 << (ui32Fsel - 1)) == i32Div) ) ? 0 : 1;
792 
793     if (ui32Phase == 1)
794     {
795         ui32LowPer = (ui32TotPer - 2) / 2;          // Longer high phase
796     }
797     else
798     {
799         ui32LowPer = (ui32TotPer - 1) / 2;          // Longer low phase
800     }
801 
802     ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_FSEL,   ui32Fsel)     |
803                  _VAL2FLD(IOM0_CLKCFG_DIV3,   ui32Div3)     |
804                  _VAL2FLD(IOM0_CLKCFG_DIVEN,  ui32DivEn)    |
805                  _VAL2FLD(IOM0_CLKCFG_LOWPER, ui32LowPer)   |
806                  _VAL2FLD(IOM0_CLKCFG_TOTPER, ui32TotPer - 1);
807 
808     //
809     // Now, compute the actual frequency, which will be returned.
810     //
811     ui32ClkFreq = compute_freq(ui32HFRCfreqHz, ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer - 1);
812 
813     //
814     // Determine if the actual frequency is a power of 2 (MHz).
815     //
816     if ( (ui32ClkFreq % 250000) == 0 )
817     {
818         //
819         // If the actual clock frequency is a power of 2 ranging from 250KHz up,
820         // we can simplify the CLKCFG value using DIV3 (which also results in a
821         // better duty cycle).
822         //
823         ui32Denomfinal = ui32ClkFreq / (uint32_t)250000;
824 
825         if ( onebit(ui32Denomfinal) )
826         {
827             //
828             // These configurations can be simplified by using DIV3.  Configs
829             // using DIV3 have a 50% duty cycle, while those from DIVEN will
830             // have a 66/33 duty cycle.
831             //
832             ui32TotPer = ui32LowPer = ui32DivEn = 0;
833             ui32Div3 = 1;
834 
835             //
836             // Now, compute the return values.
837             //
838             ui32ClkFreq = compute_freq(ui32HFRCfreqHz, ui32Fsel, ui32Div3, ui32DivEn, ui32TotPer);
839 
840     ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_FSEL,   ui32Fsel)     |
841                  _VAL2FLD(IOM0_CLKCFG_DIV3,   1)            |
842                  _VAL2FLD(IOM0_CLKCFG_DIVEN,  0)            |
843                  _VAL2FLD(IOM0_CLKCFG_LOWPER, 0)            |
844                  _VAL2FLD(IOM0_CLKCFG_TOTPER, 0);
845         }
846     }
847 
848     return ( ((uint64_t)ui32ClkFreq) << 32) | (uint64_t)ui32ClkCfg;
849 
850 } //iom_get_interface_clock_cfg()
851 
852 //*****************************************************************************
853 //
854 // @brief Initializes the IOM Command Queue.
855 //
856 // @param pHandle       - handle for the interface.
857 // @param ui32Length   - length of the SRAM Command Queue buffer in words.
858 // @param pTCB         - pointer to the SRAM to use for the Command Queue.
859 //
860 // This function initializes the global command queue structure.
861 //
862 // @return HAL status of the operation.
863 //
864 //*****************************************************************************
865 uint32_t
am_hal_iom_CQInit(void * pHandle,uint32_t ui32Length,uint32_t * pTCB)866 am_hal_iom_CQInit(void *pHandle, uint32_t ui32Length,
867                   uint32_t *pTCB)
868 {
869     am_hal_cmdq_cfg_t cqCfg;
870     am_hal_iom_state_t  *pIOMState = (am_hal_iom_state_t *)pHandle;
871     uint32_t            ui32Module = pIOMState->ui32Module;
872     uint32_t            ui32Status = AM_HAL_STATUS_SUCCESS;
873 
874     pIOMState->pCmdQHdl = NULL;
875     pIOMState->ui32MaxTransactions = 0;
876     pIOMState->ui32NumUnSolicited = 0;
877 
878     cqCfg.pCmdQBuf = pTCB;
879     cqCfg.cmdQSize = ui32Length / 2;
880     cqCfg.priority = AM_HAL_CMDQ_PRIO_HI;
881     ui32Status = am_hal_cmdq_init((am_hal_cmdq_if_e)(AM_HAL_CMDQ_IF_IOM0 + ui32Module),
882                       &cqCfg, &pIOMState->pCmdQHdl);
883     if (ui32Status == AM_HAL_STATUS_SUCCESS)
884     {
885         pIOMState->ui32MaxTransactions = AM_HAL_IOM_MAX_PENDING_TRANSACTIONS;
886     }
887     return ui32Status;
888 } // am_hal_iom_CQInit()
889 
890 //*****************************************************************************
891 //
892 // @brief Resets the IOM Command Queue.
893 //
894 // @param pHandle   - IOM handle.
895 //
896 // This function resets the global command queue structure.
897 //
898 // @return HAL status of the operation.
899 //
900 //*****************************************************************************
901 uint32_t
am_hal_IOM_CQReset(void * pHandle)902 am_hal_IOM_CQReset(void *pHandle)
903 {
904     am_hal_iom_state_t  *pIOMState = (am_hal_iom_state_t *)pHandle;
905 
906     if (pIOMState->pCmdQHdl)
907     {
908         am_hal_cmdq_term(pIOMState->pCmdQHdl, true);
909         pIOMState->pCmdQHdl = NULL;
910     }
911 
912     //
913     // Return the status.
914     //
915     return AM_HAL_STATUS_SUCCESS;
916 } // am_hal_IOM_CQReset()
917 
918 //*****************************************************************************
919 //
920 // @brief Adds a transaction the IOM Command Queue.
921 //
922 // @param pHandle       - handle for the interface.
923 // @param psTransaction - transaction to add to the CQ
924 // @param pfnCallback  - pointer the callback function to be executed when
925 //                       transaction is complete.
926 // @param pCallbackCtxt - parameter passed to callback function
927 //
928 // This function copies data from the IOM FIFO into the array \e pui32Data.
929 // This is how input data from SPI or I2C transactions may be retrieved.
930 //
931 // @return HAL status of the operation.
932 //
933 //*****************************************************************************
934 uint32_t
am_hal_iom_CQAddTransaction(void * pHandle,am_hal_iom_transfer_t * psTransaction,am_hal_iom_callback_t pfnCallback,void * pCallbackCtxt)935 am_hal_iom_CQAddTransaction(void *pHandle,
936                             am_hal_iom_transfer_t *psTransaction,
937                             am_hal_iom_callback_t pfnCallback,
938                             void *pCallbackCtxt)
939 {
940     am_hal_iom_state_t      *pIOMState = (am_hal_iom_state_t *)pHandle;
941     am_hal_iom_txn_cmdlist_t   *pCQEntry;
942     am_hal_cmdq_entry_t     *pCQBlock;
943     uint32_t                index;
944 
945     //
946     // Check to see if there is enough room in the CQ
947     //
948     if ((pIOMState->ui32NumPendTransactions == AM_HAL_IOM_MAX_PENDING_TRANSACTIONS) ||
949         (am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, sizeof(am_hal_iom_txn_cmdlist_t) / 8, &pCQBlock, &index)))
950     {
951         return AM_HAL_STATUS_OUT_OF_RANGE;
952     }
953 
954     pCQEntry = (am_hal_iom_txn_cmdlist_t *)pCQBlock;
955 
956     build_txn_cmdlist(pIOMState, pCQEntry, psTransaction);
957 
958     //
959     // Because we set AM_HAL_IOM_CQUPD_INT_FLAG, an interrupt will occur once
960     // we reach this point in the Command Queue.  In the service routine, we'll
961     // look for the appropriate callback.
962     //
963     // If ENDIDX has been reached, the CQ will pause here. Otherwise will
964     // continue with the next CQ entry.
965     //
966 
967     //
968     // Store the callback function pointer.
969     //
970     pIOMState->pfnCallback[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pfnCallback;
971     pIOMState->pCallbackCtxt[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pCallbackCtxt;
972 
973     return AM_HAL_STATUS_SUCCESS;
974 } // am_hal_iom_CQAddTransaction()
975 
976 //*****************************************************************************
977 //
978 // @brief Enable the Command Queue operation.
979 //
980 // @param pHandle       - handle for the interface.
981 //
982 // This function enables Command Queue operation.
983 //
984 //
985 // @return HAL status of the operation.
986 //
987 //
988 //*****************************************************************************
989 uint32_t
am_hal_iom_CQEnable(void * pHandle)990 am_hal_iom_CQEnable(void *pHandle)
991 {
992     am_hal_iom_state_t  *pIOMState = (am_hal_iom_state_t *)pHandle;
993 
994     if (0 == pIOMState->ui32NumPendTransactions)
995     {
996         uint32_t *pCqAddr = (uint32_t *)IOMn(pIOMState->ui32Module)->CQADDR;
997         // When CQ is enabled with nothing there - it always executes the first command
998         // insert dummy command
999         *pCqAddr = (uint32_t) &IOMn(pIOMState->ui32Module)->CQADDR;
1000         *(pCqAddr + 1) = (uint32_t)pCqAddr;
1001     }
1002     //
1003     // Enable the Command Queue operation
1004     //
1005     return am_hal_cmdq_enable(pIOMState->pCmdQHdl);
1006 
1007 } // am_hal_iom_CQEnable()
1008 
1009 //*****************************************************************************
1010 //
1011 // @brief Disable the Command Queue operation.
1012 //
1013 // @param pHandle       - handle for the interface.
1014 //
1015 // This function disables the Command Queue operation.
1016 //
1017 //
1018 // @return HAL status of the operation.
1019 //
1020 //
1021 //*****************************************************************************
1022 uint32_t
am_hal_iom_CQDisable(void * pHandle)1023 am_hal_iom_CQDisable(void *pHandle)
1024 {
1025     am_hal_iom_state_t  *pIOMState = (am_hal_iom_state_t *)pHandle;
1026 
1027     //
1028     // Disable the Command Queue operation
1029     //
1030     return am_hal_cmdq_disable(pIOMState->pCmdQHdl);
1031 } // am_hal_iom_CQDisable()
1032 
1033 //*****************************************************************************
1034 //
1035 //! @brief Dummy Callback.
1036 //!
1037 //*****************************************************************************
iom_dummy_callback(void * pCallbackCtxt,uint32_t status)1038 static void iom_dummy_callback(void *pCallbackCtxt, uint32_t status)
1039 {
1040     // Dummy - Do nothing
1041 }
1042 
1043 //*****************************************************************************
1044 //
1045 //! @brief Callback when end of sequence is reached.
1046 //!
1047 //*****************************************************************************
iom_seq_loopback(void * pCallbackCtxt,uint32_t status)1048 static void iom_seq_loopback(void *pCallbackCtxt, uint32_t status)
1049 {
1050     // Reset the state to allow serving callbacks for next set
1051     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t *)pCallbackCtxt;
1052     pIOMState->ui32NumPendTransactions = pIOMState->ui32NumSeqTransactions + 1;
1053     pIOMState->ui32LastIdxProcessed = 0;
1054     pIOMState->bRestart = true;
1055     // Now resume the CQ - to finish loopback
1056     // Resume the CQ
1057     IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_SEQLOOP;
1058 }
1059 
1060 //*****************************************************************************
1061 //
1062 //! @brief Pause the Command Queue.
1063 //!
1064 //! @param pIOMState       - pointer to the IOM internal state.
1065 //!
1066 //! This function pauses the Command Queue operation.
1067 //!
1068 //! @return HAL status of the operation.
1069 //
1070 //*****************************************************************************
iom_cq_pause(am_hal_iom_state_t * pIOMState)1071 static uint32_t iom_cq_pause(am_hal_iom_state_t *pIOMState)
1072 {
1073     uint32_t status = AM_HAL_STATUS_SUCCESS;
1074     uint32_t ui32usMaxDelay = AM_HAL_IOM_MAX_PAUSE_DELAY;
1075     // Pause the CQ
1076     IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_PAUSE_CQ;
1077     // It is possible that CQ is disabled once the last transaction is processed
1078     while ( IOMn(pIOMState->ui32Module)->CQCFG_b.CQEN )
1079     {
1080         // Need to make sure we're paused at a designated pause point
1081         if ( IOMn(pIOMState->ui32Module)->CQSTAT_b.CQPAUSED && (IOMn(pIOMState->ui32Module)->CQPAUSEEN & AM_HAL_IOM_PAUSE_FLAG_CQ) )
1082         {
1083             break;
1084         }
1085         if ( ui32usMaxDelay-- )
1086         {
1087             //
1088             // Call the BOOTROM cycle function to delay for about 1 microsecond.
1089             //
1090             am_hal_flash_delay( FLASH_CYCLES_US(1) );
1091         }
1092         else
1093         {
1094             return AM_HAL_STATUS_TIMEOUT;
1095         }
1096     }
1097     if (status == AM_HAL_STATUS_SUCCESS)
1098     {
1099         // Now that CQ is guaranteed to not progress further - we need to still wait in case the current CQ entry
1100         // resulted in a DMA state....need to make sure we finish the current DMA
1101         status = am_hal_flash_delay_status_check(AM_HAL_IOM_MAX_PAUSE_DELAY,
1102                                              (uint32_t)&IOMn(pIOMState->ui32Module)->DMASTAT,
1103                                              IOM0_DMASTAT_DMATIP_Msk,
1104                                              _VAL2FLD(IOM0_DMASTAT_DMATIP, 0),
1105                                              true);
1106 
1107     }
1108     return status;
1109 }
1110 
1111 //*****************************************************************************
1112 //
1113 //! @brief Program the DMA directly.
1114 //!
1115 //! @param pHandle       - pointer the IOM instance handle.
1116 //!
1117 //! This function pauses the Command Queue operation.
1118 //!
1119 //! @return HAL status of the operation.
1120 //
1121 //*****************************************************************************
1122 static void
program_dma(void * pHandle)1123 program_dma(void *pHandle)
1124 {
1125     am_hal_iom_state_t         *pIOMState = (am_hal_iom_state_t *)pHandle;
1126     uint32_t                    ui32Module = pIOMState->ui32Module;
1127     uint32_t                    index = (pIOMState->ui32LastHPIdxProcessed + 1) % pIOMState->ui32MaxHPTransactions;
1128     am_hal_iom_dma_entry_t     *pDMAEntry = &pIOMState->pHPTransactions[index];
1129 
1130     //
1131     // OFFSETHI
1132     //
1133     IOMn(ui32Module)->OFFSETHI = pDMAEntry->ui32OFFSETHIVal;
1134 
1135     //
1136     // I2C DEVADDR field in DEVCFG
1137     //
1138     IOMn(ui32Module)->DEVCFG = pDMAEntry->ui32DEVCFGVal;
1139 
1140     //
1141     // disable DMA before writing TOTCOUNT.
1142     //
1143     IOMn(ui32Module)->DMACFG = 0x0;
1144 
1145     //
1146     // set DMATOTALCOUNT
1147     //
1148     IOMn(ui32Module)->DMATOTCOUNT = pDMAEntry->ui32DMATOTCOUNTVal;
1149 
1150     //
1151     // set DMATARGADDR
1152     //
1153     IOMn(ui32Module)->DMATARGADDR = pDMAEntry->ui32DMATARGADDRVal;
1154 
1155     //
1156     // Command to set DMACFG to start the DMA operation
1157     //
1158     IOMn(ui32Module)->DMACFG = pDMAEntry->ui32DMACFGVal;
1159     //
1160     // Command to start the transfer.
1161     //
1162     IOMn(ui32Module)->CMD = pDMAEntry->ui32CMDVal;
1163 }
1164 
1165 //*****************************************************************************
1166 //
1167 //! @brief Schedule a high priority transaction.
1168 //!
1169 //! @param pIOMState       - pointer to the IOM internal state.
1170 //! @param numTrans        - number of transaction to schedule in a block.
1171 //!
1172 //! This function pauses the Command Queue operation.
1173 //!
1174 //! @return HAL status of the operation.
1175 //
1176 //*****************************************************************************
1177 static uint32_t
sched_hiprio(am_hal_iom_state_t * pIOMState,uint32_t numTrans)1178 sched_hiprio(am_hal_iom_state_t *pIOMState, uint32_t numTrans)
1179 {
1180     uint32_t ui32NumPend;
1181     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
1182     //
1183     // Start a critical section.
1184     //
1185     AM_CRITICAL_BEGIN
1186 
1187     ui32NumPend = pIOMState->ui32NumHPEntries;
1188     pIOMState->ui32NumHPEntries += numTrans;
1189 
1190     //
1191     // End the critical section.
1192     //
1193     AM_CRITICAL_END
1194 
1195 
1196     if (0 == ui32NumPend)
1197     {
1198         // Force CQ to Pause
1199         ui32Status = iom_cq_pause(pIOMState);
1200         if (ui32Status != AM_HAL_STATUS_SUCCESS)
1201         {
1202             return ui32Status;
1203         }
1204         pIOMState->ui32TxnInt = 0;
1205         // Clear & Enable DMACMP interrupt
1206         IOMn(pIOMState->ui32Module)->INTCLR = AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP;
1207         IOMn(pIOMState->ui32Module)->INTEN |= AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP;
1208         pIOMState->bHP = true;
1209         //
1210         // Program the DMA
1211         //
1212         program_dma(pIOMState);
1213     }
1214     return ui32Status;
1215 } // sched_hiprio()
1216 
1217 
1218 //*****************************************************************************
1219 //
1220 //! @brief Add a high priority transaction.
1221 //!
1222 //! @param pHandle       - pointer the IOM instance handle.
1223 //! @param psTransaction - pointer to IOM transaction.
1224 //! @param pfnCallback   - pointer to the callback for transaction (could be NULL).
1225 //! @param pCallbackCtxt - pointer to the context to the callback (could be NULL).
1226 //!
1227 //! This function adds a function to the internal high priority transaction queue.
1228 //!
1229 //! @return HAL status of the operation.
1230 //
1231 //*****************************************************************************
1232 static uint32_t
iom_add_hp_transaction(void * pHandle,am_hal_iom_transfer_t * psTransaction,am_hal_iom_callback_t pfnCallback,void * pCallbackCtxt)1233 iom_add_hp_transaction(void *pHandle,
1234                        am_hal_iom_transfer_t *psTransaction,
1235                        am_hal_iom_callback_t pfnCallback,
1236                        void *pCallbackCtxt)
1237 {
1238     am_hal_iom_state_t      *pIOMState = (am_hal_iom_state_t *)pHandle;
1239     am_hal_iom_dma_entry_t  *pDMAEntry;
1240     uint32_t                ui32Dir = psTransaction->eDirection;
1241     uint32_t                ui32SRAMAddress;
1242 
1243     uint32_t  index = pIOMState->ui32NextHPIdx % pIOMState->ui32MaxHPTransactions;
1244     //
1245     // Check to see if there is enough room in the queue
1246     //
1247     if ( pIOMState->ui32NumHPEntries == pIOMState->ui32MaxHPTransactions )
1248     {
1249         return AM_HAL_STATUS_OUT_OF_RANGE;
1250     }
1251 
1252     ui32SRAMAddress = (ui32Dir == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
1253     pDMAEntry = &pIOMState->pHPTransactions[index];
1254     pDMAEntry->ui32OFFSETHIVal   = (uint16_t)(psTransaction->ui32Instr >> 8);
1255     pDMAEntry->ui32DEVCFGVal     = _VAL2FLD(IOM0_DEVCFG_DEVADDR, psTransaction->uPeerInfo.ui32I2CDevAddr);
1256     pDMAEntry->ui32DMATARGADDRVal = ui32SRAMAddress;
1257     pDMAEntry->ui32DMATOTCOUNTVal  = psTransaction->ui32NumBytes;
1258     pDMAEntry->ui32DMACFGVal      =
1259         _VAL2FLD(IOM0_DMACFG_DMAPRI, psTransaction->ui8Priority)     |
1260         _VAL2FLD(IOM0_DMACFG_DMADIR, ui32Dir == AM_HAL_IOM_TX ? 1 : 0);
1261 
1262     if (psTransaction->ui32NumBytes)
1263     {
1264         pDMAEntry->ui32DMACFGVal |= IOM0_DMACFG_DMAEN_Msk;
1265     }
1266     //
1267     // Command to start the transfer.
1268     //
1269     pDMAEntry->ui32CMDVal =  build_cmd((pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) ? psTransaction->uPeerInfo.ui32SpiChipSelect : 0, // ChipSelect
1270                                 ui32Dir,          // ui32Dir
1271                                 psTransaction->bContinue,           // ui32Cont
1272                                 psTransaction->ui32Instr,           // ui32Offset
1273                                 psTransaction->ui32InstrLen,        // ui32OffsetCnt
1274                                 psTransaction->ui32NumBytes);  // ui32Bytes
1275 
1276     pDMAEntry->pfnCallback = pfnCallback;
1277     pDMAEntry->pCallbackCtxt = pCallbackCtxt;
1278 
1279     pIOMState->ui32NextHPIdx++;
1280     return AM_HAL_STATUS_SUCCESS;
1281 } // iom_add_hp_transaction()
1282 
1283 //*****************************************************************************
1284 //
1285 // @brief Validate an IOM transaction.
1286 //
1287 // @param pIOMState     - pointer to the IOM internal state.
1288 // @param psTransaction - pointer to IOM transaction.
1289 // @param bBlocking     - is this a blocking transaction?
1290 //
1291 // This function validates.
1292 //
1293 // @return HAL status of the operation.
1294 //
1295 //*****************************************************************************
1296 uint32_t
validate_transaction(am_hal_iom_state_t * pIOMState,am_hal_iom_transfer_t * psTransaction,bool bBlocking)1297 validate_transaction(am_hal_iom_state_t *pIOMState,
1298                      am_hal_iom_transfer_t *psTransaction,
1299                      bool bBlocking)
1300 {
1301     uint32_t ui32Offset, ui32OffsetCnt, ui32Dir, ui32Bytes;
1302 
1303     ui32Offset = psTransaction->ui32Instr;
1304     ui32OffsetCnt = psTransaction->ui32InstrLen;
1305     ui32Dir = psTransaction->eDirection;
1306     ui32Bytes = psTransaction->ui32NumBytes;
1307 
1308     //
1309     // Validate parameters
1310     //
1311     if ( (ui32OffsetCnt > AM_HAL_IOM_MAX_OFFSETSIZE)                            ||
1312          (ui32Offset & (0xFFFFFFFF << (ui32OffsetCnt*8)))                       ||
1313          (ui32Bytes && (ui32Dir != AM_HAL_IOM_TX) && (psTransaction->pui32RxBuffer == NULL)) ||
1314          (ui32Bytes && (ui32Dir != AM_HAL_IOM_RX) && (psTransaction->pui32TxBuffer == NULL)) ||
1315          ((pIOMState->eInterfaceMode == AM_HAL_IOM_I2C_MODE) &&
1316           (psTransaction->ui32NumBytes > AM_HAL_IOM_MAX_TXNSIZE_I2C))           ||
1317          ((pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) &&
1318           ((psTransaction->uPeerInfo.ui32SpiChipSelect > AM_HAL_IOM_MAX_CS_SPI) ||
1319            (psTransaction->ui32NumBytes > AM_HAL_IOM_MAX_TXNSIZE_SPI))) )
1320     {
1321         return AM_HAL_STATUS_INVALID_ARG;
1322     }
1323 
1324     if (!bBlocking)
1325     {
1326         if (psTransaction->ui32PauseCondition & AM_HAL_IOM_PAUSE_FLAG_RESV)
1327         {
1328             return AM_HAL_STATUS_INVALID_ARG;
1329         }
1330         if (psTransaction->ui32StatusSetClr & AM_HAL_IOM_SC_RESV_MASK)
1331         {
1332             return AM_HAL_STATUS_INVALID_ARG;
1333         }
1334     }
1335 
1336     return AM_HAL_STATUS_SUCCESS;
1337 
1338 } // validate_transaction()
1339 
1340 //*****************************************************************************
1341 //
1342 // IOM uninitialize function
1343 //
1344 //*****************************************************************************
1345 uint32_t
am_hal_iom_uninitialize(void * pHandle)1346 am_hal_iom_uninitialize(void *pHandle)
1347 {
1348     uint32_t status = AM_HAL_STATUS_SUCCESS;
1349     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
1350 
1351 #ifndef AM_HAL_DISABLE_API_VALIDATION
1352     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1353     {
1354         return AM_HAL_STATUS_INVALID_HANDLE;
1355     }
1356 #endif // AM_HAL_DISABLE_API_VALIDATION
1357 
1358     if (pIOMState->prefix.s.bEnable)
1359     {
1360         am_hal_iom_disable(pHandle);
1361     }
1362 
1363     pIOMState->prefix.s.bInit = false;
1364 
1365     //
1366     // Return the status.
1367     //
1368     return status;
1369 
1370 } // am_hal_iom_uninitialize()
1371 
1372 //*****************************************************************************
1373 //
1374 // IOM initialization function
1375 //
1376 //*****************************************************************************
1377 uint32_t
am_hal_iom_initialize(uint32_t ui32Module,void ** ppHandle)1378 am_hal_iom_initialize(uint32_t ui32Module, void **ppHandle)
1379 {
1380     // Compile time check to ensure ENTRY_SIZE macros are defined correctly
1381     // incorrect definition will cause divide by 0 error at build time
1382     am_ct_assert((sizeof(am_hal_iom_txn_cmdlist_t) + 8) == AM_HAL_IOM_CQ_ENTRY_SIZE);
1383     am_ct_assert(sizeof(am_hal_iom_dma_entry_t) == AM_HAL_IOM_HIPRIO_ENTRY_SIZE);
1384 
1385 #ifndef AM_HAL_DISABLE_API_VALIDATION
1386     //
1387     // Validate the module number
1388     //
1389     if ( ui32Module >= AM_REG_IOM_NUM_MODULES )
1390     {
1391         return AM_HAL_STATUS_OUT_OF_RANGE;
1392     }
1393 
1394     if (ppHandle == NULL)
1395     {
1396         return AM_HAL_STATUS_INVALID_ARG;
1397     }
1398 
1399     if (g_IOMhandles[ui32Module].prefix.s.bInit)
1400     {
1401         return AM_HAL_STATUS_INVALID_OPERATION;
1402     }
1403 #endif // AM_HAL_DISABLE_API_VALIDATION
1404 
1405     g_IOMhandles[ui32Module].prefix.s.bInit = true;
1406     g_IOMhandles[ui32Module].prefix.s.bEnable = false;
1407     g_IOMhandles[ui32Module].prefix.s.magic = AM_HAL_MAGIC_IOM;
1408 
1409     //
1410     // Initialize the handle.
1411     //
1412     g_IOMhandles[ui32Module].ui32Module = ui32Module;
1413 
1414     //
1415     // Return the handle.
1416     //
1417     *ppHandle = (void *)&g_IOMhandles[ui32Module];
1418 
1419     //
1420     // Return the status
1421     //
1422     return AM_HAL_STATUS_SUCCESS;
1423 
1424 } // am_hal_iom_initialize()
1425 
1426 //*****************************************************************************
1427 //
1428 // IOM enable function
1429 //
1430 //*****************************************************************************
1431 uint32_t
am_hal_iom_enable(void * pHandle)1432 am_hal_iom_enable(void *pHandle)
1433 {
1434     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
1435     uint32_t status = AM_HAL_STATUS_SUCCESS;
1436 #ifndef AM_HAL_DISABLE_API_VALIDATION
1437     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1438     {
1439         return AM_HAL_STATUS_INVALID_HANDLE;
1440     }
1441 
1442     if (pIOMState->prefix.s.bEnable)
1443     {
1444         return AM_HAL_STATUS_SUCCESS;
1445     }
1446 #endif // AM_HAL_DISABLE_API_VALIDATION
1447 
1448     // Enable submodule
1449 #if 1
1450     enable_submodule(pIOMState->ui32Module, ((pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE) ? 0 : 1));
1451 #endif
1452 
1453 #if MANUAL_POP
1454     IOMn(pIOMState->ui32Module)->FIFOCTRL_b.POPWR = 1;
1455 #endif
1456 
1457     //
1458     // If Enable the Command Queue
1459     //
1460     if ( pIOMState->pNBTxnBuf )
1461     {
1462         pIOMState->ui32NumPendTransactions = 0;
1463         pIOMState->ui32LastIdxProcessed = 0;
1464         // Initialize Flags used to force CQ Pause
1465         IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_CQ | AM_HAL_IOM_SC_PAUSE_SEQLOOP;
1466         pIOMState->pHPTransactions = NULL;
1467         pIOMState->bHP = false;
1468         pIOMState->block = 0;
1469         pIOMState->ui32NumHPPendingEntries = 0;
1470         pIOMState->ui32NumHPEntries = 0;
1471         pIOMState->eSeq = AM_HAL_IOM_SEQ_NONE;
1472         pIOMState->ui32NumSeqTransactions = 0;
1473         pIOMState->bAutonomous = true;
1474         status = am_hal_iom_CQInit(pIOMState,
1475                                    pIOMState->ui32NBTxnBufLength,
1476                                    pIOMState->pNBTxnBuf);
1477         // Initialize the DMA Trigger Setting
1478         //
1479         // DMATRIG, set DTHREN and/or DCMDCMPEN.
1480         // Note - it is recommended that DTHREN always be set.
1481         //
1482         IOMn(pIOMState->ui32Module)->DMATRIGEN = _VAL2FLD(IOM0_DMATRIGEN_DTHREN, 1);
1483     }
1484 
1485     if (status == AM_HAL_STATUS_SUCCESS)
1486     {
1487         pIOMState->prefix.s.bEnable = true;
1488     }
1489 
1490     //
1491     // We're done, return the status.
1492     //
1493     return status;
1494 
1495 } // am_hal_iom_enable()
1496 
1497 //*****************************************************************************
1498 //
1499 // IOM disable function
1500 //
1501 //*****************************************************************************
1502 uint32_t
am_hal_iom_disable(void * pHandle)1503 am_hal_iom_disable(void *pHandle)
1504 {
1505   am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
1506 
1507 #ifndef AM_HAL_DISABLE_API_VALIDATION
1508   if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1509   {
1510     return AM_HAL_STATUS_INVALID_HANDLE;
1511   }
1512 #endif // AM_HAL_DISABLE_API_VALIDATION
1513 
1514   if (!pIOMState->prefix.s.bEnable)
1515   {
1516     return AM_HAL_STATUS_SUCCESS;
1517   }
1518 
1519   // Check if we have any pending transactions.
1520   if (pIOMState->ui32NumPendTransactions)
1521   {
1522     return AM_HAL_STATUS_IN_USE;
1523   }
1524 
1525   //
1526   // Disable the submodules
1527   //
1528   IOMn(pIOMState->ui32Module)->SUBMODCTRL_b.SMOD0EN = 0;
1529   IOMn(pIOMState->ui32Module)->SUBMODCTRL_b.SMOD1EN = 0;
1530 
1531   am_hal_IOM_CQReset(pHandle);
1532 
1533   pIOMState->prefix.s.bEnable = false;
1534 
1535   //
1536   // Return the status.
1537   //
1538   return AM_HAL_STATUS_SUCCESS;
1539 
1540 } // am_hal_iom_disable()
1541 
1542 //*****************************************************************************
1543 //
1544 // IOM get status function
1545 //
1546 //*****************************************************************************
1547 uint32_t
am_hal_iom_status_get(void * pHandle,am_hal_iom_status_t * psStatus)1548 am_hal_iom_status_get(void *pHandle, am_hal_iom_status_t *psStatus)
1549 {
1550     uint32_t ui32Module, ui32IomStat;
1551     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
1552 
1553 #ifndef AM_HAL_DISABLE_API_VALIDATION
1554     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1555     {
1556         return AM_HAL_STATUS_INVALID_HANDLE;
1557     }
1558     if (!psStatus)
1559     {
1560         return AM_HAL_STATUS_INVALID_ARG;
1561     }
1562 #endif // AM_HAL_DISABLE_API_VALIDATION
1563 
1564     ui32Module = pIOMState->ui32Module;
1565 
1566     //
1567     // Begin critical section while we gather status information.
1568     //
1569     AM_CRITICAL_BEGIN
1570 
1571     ui32IomStat = IOMn(ui32Module)->STATUS;
1572     psStatus->bStatIdle   = _FLD2VAL(IOM0_STATUS_IDLEST, ui32IomStat);
1573     psStatus->bStatErr    = _FLD2VAL(IOM0_STATUS_ERR,    ui32IomStat);
1574     psStatus->bStatCmdAct = _FLD2VAL(IOM0_STATUS_CMDACT, ui32IomStat);
1575 
1576     //
1577     // Return all the bitfields of DMASTAT.
1578     //
1579     psStatus->ui32DmaStat = IOMn(ui32Module)->DMASTAT;
1580 
1581     psStatus->ui32MaxTransactions = pIOMState->ui32MaxTransactions;
1582     psStatus->ui32NumPendTransactions = pIOMState->ui32NumPendTransactions;
1583 
1584     //
1585     // End the critical section.
1586     //
1587     AM_CRITICAL_END
1588 
1589     //
1590     // Return the status.
1591     //
1592     return AM_HAL_STATUS_SUCCESS;
1593 
1594 } // am_hal_iom_status_get()
1595 
1596 //*****************************************************************************
1597 //
1598 // IOM enable interrupts function
1599 //
1600 //*****************************************************************************
1601 uint32_t
am_hal_iom_interrupt_enable(void * pHandle,uint32_t ui32IntMask)1602 am_hal_iom_interrupt_enable(void *pHandle, uint32_t ui32IntMask)
1603 {
1604     uint32_t ui32Module;
1605 
1606 #ifndef AM_HAL_DISABLE_API_VALIDATION
1607     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1608     {
1609         return AM_HAL_STATUS_INVALID_HANDLE;
1610     }
1611 #endif // AM_HAL_DISABLE_API_VALIDATION
1612 
1613     if (ui32IntMask & AM_HAL_IOM_INT_THR)
1614     {
1615       return AM_HAL_STATUS_INVALID_ARG;  // Threshold Interupt should not be used.
1616     }
1617 
1618     ui32Module = ((am_hal_iom_state_t*)pHandle)->ui32Module;
1619 
1620     //
1621     // Set the interrupt enables according to the mask.
1622     //
1623     IOMn(ui32Module)->INTEN |= ui32IntMask;
1624 
1625     //
1626     // Return the status.
1627     //
1628     return AM_HAL_STATUS_SUCCESS;
1629 
1630 } // am_hal_iom_interrupt_enable()
1631 
1632 //*****************************************************************************
1633 //
1634 // IOM disable interrupts function
1635 //
1636 //*****************************************************************************
1637 uint32_t
am_hal_iom_interrupt_disable(void * pHandle,uint32_t ui32IntMask)1638 am_hal_iom_interrupt_disable(void *pHandle, uint32_t ui32IntMask)
1639 {
1640     uint32_t ui32Module;
1641 
1642 #ifndef AM_HAL_DISABLE_API_VALIDATION
1643     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1644     {
1645         return AM_HAL_STATUS_INVALID_HANDLE;
1646     }
1647 #endif // AM_HAL_DISABLE_API_VALIDATION
1648 
1649     ui32Module = ((am_hal_iom_state_t*)pHandle)->ui32Module;
1650 
1651     //
1652     // Clear the interrupt enables according to the mask.
1653     //
1654     IOMn(ui32Module)->INTEN &= ~ui32IntMask;
1655 
1656     //
1657     // Return the status.
1658     //
1659     return AM_HAL_STATUS_SUCCESS;
1660 
1661 } // am_hal_iom_interrupt_disable()
1662 
1663 //*****************************************************************************
1664 //
1665 // IOM get interrupt status
1666 //
1667 //*****************************************************************************
1668 uint32_t
am_hal_iom_interrupt_status_get(void * pHandle,bool bEnabledOnly,uint32_t * pui32IntStatus)1669 am_hal_iom_interrupt_status_get(void *pHandle, bool bEnabledOnly,
1670                                 uint32_t *pui32IntStatus)
1671 {
1672     uint32_t ui32IntStatus;
1673     uint32_t ui32Module;
1674 
1675 #ifndef AM_HAL_DISABLE_API_VALIDATION
1676     if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
1677     {
1678         return AM_HAL_STATUS_INVALID_HANDLE;
1679     }
1680 
1681     if ( !pui32IntStatus )
1682     {
1683         return AM_HAL_STATUS_INVALID_ARG;
1684     }
1685 #endif // AM_HAL_DISABLE_API_VALIDATION
1686 
1687     ui32Module = ((am_hal_iom_state_t*)pHandle)->ui32Module;
1688 
1689     ui32IntStatus = IOMn(ui32Module)->INTSTAT;
1690 
1691     if ( bEnabledOnly )
1692     {
1693         ui32IntStatus &= IOMn(ui32Module)->INTEN;
1694     }
1695 
1696     *pui32IntStatus = ui32IntStatus;
1697 
1698     //
1699     // Return the status.
1700     //
1701     return AM_HAL_STATUS_SUCCESS;
1702 
1703 } // am_hal_iom_interrupt_status_get()
1704 
1705 //*****************************************************************************
1706 //
1707 // IOM interrupt clear
1708 //
1709 //*****************************************************************************
1710 uint32_t
am_hal_iom_interrupt_clear(void * pHandle,uint32_t ui32IntMask)1711 am_hal_iom_interrupt_clear(void *pHandle, uint32_t ui32IntMask)
1712 {
1713     uint32_t ui32Module;
1714 
1715 #ifndef AM_HAL_DISABLE_API_VALIDATION
1716     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1717     {
1718         return AM_HAL_STATUS_INVALID_HANDLE;
1719     }
1720 #endif // AM_HAL_DISABLE_API_VALIDATION
1721     ui32Module = ((am_hal_iom_state_t*)pHandle)->ui32Module;
1722 
1723     //
1724     // Clear the requested interrupts.
1725     //
1726     IOMn(ui32Module)->INTCLR = ui32IntMask;
1727 
1728     //
1729     // Return the status.
1730     //
1731     return AM_HAL_STATUS_SUCCESS;
1732 
1733 } // am_hal_iom_interrupt_clear()
1734 
1735 //*****************************************************************************
1736 //
1737 // IOM interrupt service routine
1738 //
1739 //*****************************************************************************
am_hal_iom_interrupt_service(void * pHandle,uint32_t ui32IntMask)1740 uint32_t am_hal_iom_interrupt_service(void *pHandle, uint32_t ui32IntMask)
1741 {
1742     uint32_t ui32Module;
1743     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
1744     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
1745     uint32_t index;
1746 
1747 #ifndef AM_HAL_DISABLE_API_VALIDATION
1748     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1749     {
1750         return AM_HAL_STATUS_INVALID_HANDLE;
1751     }
1752 #endif // AM_HAL_DISABLE_API_VALIDATION
1753 
1754     ui32Module = pIOMState->ui32Module;
1755 
1756     if (pIOMState->bHP)
1757     {
1758         //
1759         // Accumulate the INTSTAT for this transaction
1760         //
1761         pIOMState->ui32TxnInt |= ui32IntMask;
1762 
1763         //
1764         // Check for the command completion
1765         //
1766         if (pIOMState->ui32TxnInt & (AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_DERR))
1767         {
1768             //
1769             // We need to wait for the DMA complete as well
1770             // Special case for 0 length DMA - by checking the DMAEN register
1771             //
1772             if ((IOMn(ui32Module)->DMACFG_b.DMAEN == 0) || (pIOMState->ui32TxnInt & (AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_ERR)))
1773             {
1774                 // Call the callback
1775                 // Need to determine the error, call the callback with proper status
1776                 pIOMState->ui32LastHPIdxProcessed++;
1777                 pIOMState->ui32NumHPEntries--;
1778                 index = pIOMState->ui32LastHPIdxProcessed % pIOMState->ui32MaxHPTransactions;
1779                 am_hal_iom_dma_entry_t *pDMAEntry = &pIOMState->pHPTransactions[index];
1780                 if ( pDMAEntry->pfnCallback != NULL )
1781                 {
1782                     pDMAEntry->pfnCallback(pDMAEntry->pCallbackCtxt, internal_iom_get_int_err(ui32Module, pIOMState->ui32TxnInt));
1783                     pDMAEntry->pfnCallback = NULL;
1784                 }
1785 
1786                 if (pIOMState->ui32TxnInt & AM_HAL_IOM_INT_ERR)
1787                 {
1788                     //
1789                     // Do Error recovery
1790                     // Disable DMA
1791                     //
1792                     IOMn(ui32Module)->DMACFG_b.DMAEN = 0;
1793 
1794                     //
1795                     // Clear DMAERR in DMASTAT
1796                     //
1797                     IOMn(ui32Module)->DMASTAT = 0;
1798 
1799                     //
1800                     // Reset Submodule & FIFO
1801                     //
1802                     internal_iom_reset_on_error(pIOMState, pIOMState->ui32TxnInt & AM_HAL_IOM_INT_ERR);
1803                 }
1804                 //
1805                 // Post next transaction if queue is not empty
1806                 //
1807                 if (pIOMState->ui32NumHPEntries)
1808                 {
1809                     //
1810                     // Initialize the DMA state machine (clear the DMACPL flag).
1811                     //
1812                     IOMn(ui32Module)->DMASTAT = 0;
1813                     //AM_REGn(IOM, ui32Module, INTCLR) = AM_HAL_IOM_INT_ALL;
1814                     pIOMState->ui32TxnInt = 0;
1815                     program_dma(pIOMState);
1816                 }
1817                 else
1818                 {
1819                     pIOMState->bHP = false;
1820                     // Unpause the CQ
1821                     // Restore interrupts
1822                     IOMn(ui32Module)->INTEN &= ~(AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP);
1823                     // Resume the CQ
1824                     IOMn(ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_CQ;
1825                 }
1826             }
1827         }
1828         return AM_HAL_STATUS_SUCCESS;
1829     }
1830     if (pIOMState->ui32NumPendTransactions)
1831     {
1832         am_hal_cmdq_status_t status;
1833 
1834         //
1835         // Get the current and last indexes.
1836         //
1837         if (pIOMState->pCmdQHdl && ((ui32Status = am_hal_cmdq_get_status(pIOMState->pCmdQHdl, &status)) == AM_HAL_STATUS_SUCCESS))
1838         {
1839             // For Sequence - this can be updated in the callback
1840             pIOMState->bRestart = false;
1841             //
1842             // Figure out which callbacks need to be handled.
1843             //
1844             while ((pIOMState->ui32LastIdxProcessed != status.lastIdxProcessed) && !(pIOMState->bRestart))
1845             {
1846                 pIOMState->ui32LastIdxProcessed++;
1847                 pIOMState->ui32NumPendTransactions--;
1848                 index = pIOMState->ui32LastIdxProcessed & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1);
1849                 if ( pIOMState->pfnCallback[index] != NULL )
1850                 {
1851                     pIOMState->pfnCallback[index](pIOMState->pCallbackCtxt[index], AM_HAL_STATUS_SUCCESS);
1852                     if (pIOMState->eSeq != AM_HAL_IOM_SEQ_RUNNING)
1853                     {
1854                         pIOMState->pfnCallback[index] = NULL;
1855                     }
1856                 }
1857             }
1858 
1859             // For Sequence - this can be updated in the callback
1860             if (!pIOMState->bRestart)
1861             {
1862                 //
1863                 // Check the CQError - If set it indicates that the current transaction encountered an error
1864                 //
1865                 if (ui32IntMask & AM_HAL_IOM_INT_ERR)
1866                 {
1867                     // Need to determine the error, call the callback with proper status
1868                     pIOMState->ui32LastIdxProcessed++;
1869                     pIOMState->ui32NumPendTransactions--;
1870                     index = pIOMState->ui32LastIdxProcessed & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1);
1871                     if ( pIOMState->pfnCallback[index] != NULL )
1872                     {
1873                         pIOMState->pfnCallback[index](pIOMState->pCallbackCtxt[index], internal_iom_get_int_err(ui32Module, ui32IntMask));
1874                         if (pIOMState->eSeq != AM_HAL_IOM_SEQ_RUNNING)
1875                         {
1876                             pIOMState->pfnCallback[index] = NULL;
1877                         }
1878                     }
1879 
1880                     //
1881                     // Do Error recovery
1882                     // Disable CQ
1883                     //
1884                     IOMn(ui32Module)->CQCFG_b.CQEN = 0;
1885 
1886                     //
1887                     // Disable DMA
1888                     //
1889                     IOMn(ui32Module)->DMACFG_b.DMAEN = 0;
1890 
1891                     //
1892                     // Clear DMAERR in DMASTAT
1893                     //
1894                     IOMn(ui32Module)->DMASTAT = 0;
1895 
1896                     //
1897                     // Reset Submodule & FIFO
1898                     //
1899                     internal_iom_reset_on_error(pIOMState, ui32IntMask & AM_HAL_IOM_INT_ERR);
1900 
1901                     //
1902                     // Move the command queue at next transaction
1903                     //
1904                     am_hal_cmdq_error_resume(pIOMState->pCmdQHdl);
1905                     if (pIOMState->ui32NumPendTransactions)
1906                     {
1907                         // Re-enable the CQ
1908                         am_hal_iom_CQEnable(pIOMState);
1909                     }
1910                 }
1911             }
1912 
1913             if (pIOMState->ui32NumPendTransactions == 0)
1914             {
1915                 //
1916                 // Disable the Command Queue
1917                 //
1918                 am_hal_iom_CQDisable(pHandle);
1919             }
1920         }
1921 
1922         if (pIOMState->ui32NumPendTransactions == 0)
1923         {
1924             //
1925             // Clear interrupts
1926             // Restore IOM interrupts.
1927             //
1928             IOM_SET_INTEN(ui32Module, pIOMState->ui32UserIntCfg);
1929         }
1930     }
1931 
1932     //
1933     // Return the status.
1934     //
1935     return ui32Status;
1936 
1937 } // am_hal_iom_interrupt_service()
1938 
1939 //*****************************************************************************
1940 //
1941 // IOM power control function
1942 //
1943 //*****************************************************************************
1944 uint32_t
am_hal_iom_power_ctrl(void * pHandle,am_hal_sysctrl_power_state_e ePowerState,bool bRetainState)1945 am_hal_iom_power_ctrl(void *pHandle,
1946                       am_hal_sysctrl_power_state_e ePowerState,
1947                       bool bRetainState)
1948 {
1949     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
1950 
1951 #ifndef AM_HAL_DISABLE_API_VALIDATION
1952     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
1953     {
1954         return AM_HAL_STATUS_INVALID_HANDLE;
1955     }
1956 #endif // AM_HAL_DISABLE_API_VALIDATION
1957 
1958     //
1959     // Decode the requested power state and update IOM operation accordingly.
1960     //
1961     switch (ePowerState)
1962     {
1963         case AM_HAL_SYSCTRL_WAKE:
1964             if (bRetainState && !pIOMState->registerState.bValid)
1965             {
1966                 return AM_HAL_STATUS_INVALID_OPERATION;
1967             }
1968 
1969             //
1970             // Enable power control.
1971             //
1972             if ( AM_HAL_STATUS_SUCCESS != am_hal_pwrctrl_periph_enable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_IOM0 + pIOMState->ui32Module)) )
1973             {
1974                 return AM_HAL_STATUS_HW_ERR;
1975             }
1976 
1977             if (bRetainState)
1978             {
1979                 //
1980                 // Restore IOM registers
1981                 IOMn(pIOMState->ui32Module)->FIFOTHR    = pIOMState->registerState.regFIFOTHR;
1982                 IOMn(pIOMState->ui32Module)->CLKCFG     = pIOMState->registerState.regCLKCFG;
1983                 IOMn(pIOMState->ui32Module)->SUBMODCTRL = pIOMState->registerState.regSUBMODCTRL;
1984                 IOMn(pIOMState->ui32Module)->CQADDR     = pIOMState->registerState.regCQADDR;
1985                 IOMn(pIOMState->ui32Module)->CQPAUSEEN  = pIOMState->registerState.regCQPAUSEEN;
1986                 IOMn(pIOMState->ui32Module)->CQCURIDX   = pIOMState->registerState.regCQCURIDX;
1987                 IOMn(pIOMState->ui32Module)->CQENDIDX   = pIOMState->registerState.regCQENDIDX;
1988                 IOMn(pIOMState->ui32Module)->MSPICFG    = pIOMState->registerState.regMSPICFG;
1989                 IOMn(pIOMState->ui32Module)->MI2CCFG    = pIOMState->registerState.regMI2CCFG;
1990                 IOMn(pIOMState->ui32Module)->INTEN      = pIOMState->registerState.regINTEN;
1991                 IOMn(pIOMState->ui32Module)->DMATRIGEN  = pIOMState->registerState.regDMATRIGEN;
1992 
1993                 // CQFGLAGS are Read-Only and hence can not be directly restored.
1994                 // We can try to restore the SWFlags here. Hardware flags depend on external conditions
1995                 // and hence can not be restored (assuming the external conditions remain the same, it should be set automatically.
1996                 IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_SET(pIOMState->registerState.regCQFLAGS & 0xFF);
1997                 //
1998                 // Set CQCFG last - can not set the enable yet
1999                 //
2000                 IOMn(pIOMState->ui32Module)->CQCFG      = pIOMState->registerState.regCQCFG & ~_VAL2FLD(IOM0_CQCFG_CQEN, IOM0_CQCFG_CQEN_EN);
2001                 if (pIOMState->registerState.regCQCFG & _VAL2FLD(IOM0_CQCFG_CQEN, IOM0_CQCFG_CQEN_EN))
2002                 {
2003                     am_hal_iom_CQEnable(pIOMState);
2004                 }
2005                 pIOMState->registerState.bValid = false;
2006             }
2007             break;
2008 
2009         case AM_HAL_SYSCTRL_NORMALSLEEP:
2010         case AM_HAL_SYSCTRL_DEEPSLEEP:
2011             // Make sure IOM is not active currently
2012             if (pIOMState->prefix.s.bEnable &&
2013                 (((IOMn(pIOMState->ui32Module)->STATUS & (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk)) != IOM0_STATUS_IDLEST_Msk) ||
2014                    pIOMState->ui32NumPendTransactions))
2015             {
2016                 return AM_HAL_STATUS_IN_USE;
2017             }
2018             if (bRetainState)
2019             {
2020                 // Save IOM Registers
2021                 pIOMState->registerState.regFIFOTHR    = IOMn(pIOMState->ui32Module)->FIFOTHR;
2022                 pIOMState->registerState.regCLKCFG     = IOMn(pIOMState->ui32Module)->CLKCFG;
2023                 pIOMState->registerState.regSUBMODCTRL = IOMn(pIOMState->ui32Module)->SUBMODCTRL;
2024                 pIOMState->registerState.regCQCFG      = IOMn(pIOMState->ui32Module)->CQCFG;
2025                 pIOMState->registerState.regCQADDR     = IOMn(pIOMState->ui32Module)->CQADDR;
2026                 pIOMState->registerState.regCQFLAGS    = IOMn(pIOMState->ui32Module)->CQFLAGS;
2027                 pIOMState->registerState.regCQPAUSEEN  = IOMn(pIOMState->ui32Module)->CQPAUSEEN;
2028                 pIOMState->registerState.regCQCURIDX   = IOMn(pIOMState->ui32Module)->CQCURIDX;
2029                 pIOMState->registerState.regCQENDIDX   = IOMn(pIOMState->ui32Module)->CQENDIDX;
2030                 pIOMState->registerState.regMSPICFG    = IOMn(pIOMState->ui32Module)->MSPICFG;
2031                 pIOMState->registerState.regMI2CCFG    = IOMn(pIOMState->ui32Module)->MI2CCFG;
2032                 pIOMState->registerState.regINTEN      = IOMn(pIOMState->ui32Module)->INTEN;
2033                 pIOMState->registerState.regDMATRIGEN  = IOMn(pIOMState->ui32Module)->DMATRIGEN;
2034 
2035                 if (IOMn(pIOMState->ui32Module)->CQCFG & _VAL2FLD(IOM0_CQCFG_CQEN, IOM0_CQCFG_CQEN_EN))
2036                 {
2037                     am_hal_iom_CQDisable(pIOMState);
2038                 }
2039 
2040                 pIOMState->registerState.bValid = true;
2041             }
2042 
2043             //
2044             // Disable power control.
2045             //
2046             if ( AM_HAL_STATUS_SUCCESS != am_hal_pwrctrl_periph_disable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_IOM0 + pIOMState->ui32Module)) )
2047             {
2048                 return AM_HAL_STATUS_HW_ERR;
2049             }
2050             break;
2051 
2052         default:
2053             return AM_HAL_STATUS_INVALID_ARG;
2054     }
2055 
2056     //
2057     // Return the status.
2058     //
2059     return AM_HAL_STATUS_SUCCESS;
2060 
2061 } // am_hal_iom_power_ctrl()
2062 
2063 //*****************************************************************************
2064 //
2065 // IOM configuration function.
2066 //
2067 //*****************************************************************************
2068 uint32_t
am_hal_iom_configure(void * pHandle,am_hal_iom_config_t * psConfig)2069 am_hal_iom_configure(void *pHandle, am_hal_iom_config_t *psConfig)
2070 {
2071     uint32_t ui32ClkCfg;
2072     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
2073     uint32_t status = AM_HAL_STATUS_SUCCESS;
2074     uint32_t ui32Module;
2075 
2076 #ifndef AM_HAL_DISABLE_API_VALIDATION
2077     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
2078     {
2079         return AM_HAL_STATUS_INVALID_HANDLE;
2080     }
2081 
2082     //
2083     // Validate the parameters
2084     //
2085     if ( (pHandle == NULL)      ||
2086          (psConfig == NULL)     ||
2087          (pIOMState->ui32Module >= AM_REG_IOM_NUM_MODULES) )
2088     {
2089         return AM_HAL_STATUS_INVALID_ARG;
2090     }
2091     // Configure not allowed in Enabled state
2092     if (pIOMState->prefix.s.bEnable)
2093     {
2094         return AM_HAL_STATUS_INVALID_OPERATION;
2095     }
2096     //
2097     // Check for DMA to/from DTCM.
2098     //
2099     if ( ((uint32_t)psConfig->pNBTxnBuf >= AM_HAL_FLASH_DTCM_START) &&
2100       ((uint32_t)psConfig->pNBTxnBuf <= AM_HAL_FLASH_DTCM_END) )
2101     {
2102       return AM_HAL_STATUS_OUT_OF_RANGE;
2103     }
2104 #endif // AM_HAL_DISABLE_API_VALIDATION
2105 
2106     ui32Module = pIOMState->ui32Module;
2107     //
2108     // Save the interface mode and chip select in the global handle.
2109     //
2110     pIOMState->eInterfaceMode = psConfig->eInterfaceMode;
2111 
2112     //
2113     // Set the IOM read/write FIFO thresholds to default values.
2114     //
2115     IOMn(ui32Module)->FIFOTHR =
2116         _VAL2FLD(IOM0_FIFOTHR_FIFORTHR, 16) |
2117         _VAL2FLD(IOM0_FIFOTHR_FIFOWTHR, 16);
2118 
2119     if ( psConfig->eInterfaceMode == AM_HAL_IOM_SPI_MODE )
2120     {
2121 #ifndef AM_HAL_DISABLE_API_VALIDATION
2122         //
2123         // Validate the SPI mode
2124         //
2125         if ( psConfig->eSpiMode > AM_HAL_IOM_SPI_MODE_3 )
2126         {
2127             return AM_HAL_STATUS_INVALID_ARG;
2128         }
2129         if (psConfig->ui32ClockFreq > AM_HAL_IOM_MAX_FREQ)
2130         {
2131             return AM_HAL_STATUS_INVALID_ARG;
2132         }
2133 #endif // AM_HAL_DISABLE_API_VALIDATION
2134 
2135         //
2136         // Determine the CLKCFG value for SPI.
2137         //
2138         ui32ClkCfg = iom_get_interface_clock_cfg(psConfig->ui32ClockFreq, (psConfig->eSpiMode & 2) >> 1);
2139 
2140         //
2141         // Set the SPI configuration.
2142         //
2143         IOMn(ui32Module)->MSPICFG =
2144             ( ((psConfig->eSpiMode << IOM0_MSPICFG_SPOL_Pos) & (IOM0_MSPICFG_SPHA_Msk | IOM0_MSPICFG_SPOL_Msk))  |
2145              _VAL2FLD(IOM0_MSPICFG_FULLDUP, 0)                              |
2146              _VAL2FLD(IOM0_MSPICFG_WTFC,    IOM0_MSPICFG_WTFC_DIS)          |
2147              _VAL2FLD(IOM0_MSPICFG_RDFC,    IOM0_MSPICFG_RDFC_DIS)          |
2148              _VAL2FLD(IOM0_MSPICFG_MOSIINV, IOM0_MSPICFG_MOSIINV_NORMAL)    |
2149              _VAL2FLD(IOM0_MSPICFG_WTFCIRQ, IOM0_MSPICFG_WTFCIRQ_MISO)      |
2150              _VAL2FLD(IOM0_MSPICFG_WTFCPOL, IOM0_MSPICFG_WTFCPOL_HIGH)      |
2151              _VAL2FLD(IOM0_MSPICFG_RDFCPOL, IOM0_MSPICFG_RDFCPOL_HIGH)      |
2152              _VAL2FLD(IOM0_MSPICFG_SPILSB,  IOM0_MSPICFG_SPILSB_MSB)        |
2153              _VAL2FLD(IOM0_MSPICFG_DINDLY,  0)                              |
2154              _VAL2FLD(IOM0_MSPICFG_DOUTDLY, 0)                              |
2155              _VAL2FLD(IOM0_MSPICFG_MSPIRST, 0) );
2156     }
2157     else if ( psConfig->eInterfaceMode == AM_HAL_IOM_I2C_MODE )
2158     {
2159         switch (psConfig->ui32ClockFreq)
2160         {
2161             case AM_HAL_IOM_100KHZ:
2162                 //
2163                 // settings below should give ~100 kHz
2164                 //
2165                 ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_TOTPER, 0x77)                     |
2166                              _VAL2FLD(IOM0_CLKCFG_LOWPER, 0x3B)                     |
2167                              _VAL2FLD(IOM0_CLKCFG_DIVEN, IOM0_CLKCFG_DIVEN_EN)      |
2168                              _VAL2FLD(IOM0_CLKCFG_DIV3, IOM0_CLKCFG_DIV3_DIS)       |
2169                              _VAL2FLD(IOM0_CLKCFG_FSEL, IOM0_CLKCFG_FSEL_HFRC_DIV2) |
2170                              _VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
2171                 IOMn(ui32Module)->MI2CCFG = _VAL2FLD(IOM0_MI2CCFG_STRDIS, 0)                            |
2172                                             _VAL2FLD(IOM0_MI2CCFG_SMPCNT, 3)                            |
2173                                             _VAL2FLD(IOM0_MI2CCFG_SDAENDLY, 15)                         |
2174                                             _VAL2FLD(IOM0_MI2CCFG_SCLENDLY, 0)                          |
2175                                             _VAL2FLD(IOM0_MI2CCFG_MI2CRST, 1)                           |
2176                                             _VAL2FLD(IOM0_MI2CCFG_SDADLY, 3)                            |
2177                                             _VAL2FLD(IOM0_MI2CCFG_ARBEN, IOM0_MI2CCFG_ARBEN_ARBDIS)     |
2178                                             _VAL2FLD(IOM0_MI2CCFG_I2CLSB, IOM0_MI2CCFG_I2CLSB_MSBFIRST) |
2179                                             _VAL2FLD(IOM0_MI2CCFG_ADDRSZ, IOM0_MI2CCFG_ADDRSZ_ADDRSZ7);
2180                 break;
2181             case AM_HAL_IOM_400KHZ:
2182                 //
2183                 // settings below should give ~400 kHz
2184                 //
2185                 ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_TOTPER, 0x1D)                     |
2186                              _VAL2FLD(IOM0_CLKCFG_LOWPER, 0x0E)                     |
2187                              _VAL2FLD(IOM0_CLKCFG_DIVEN, IOM0_CLKCFG_DIVEN_EN)      |
2188                              _VAL2FLD(IOM0_CLKCFG_DIV3, IOM0_CLKCFG_DIV3_DIS)       |
2189                              _VAL2FLD(IOM0_CLKCFG_FSEL, IOM0_CLKCFG_FSEL_HFRC_DIV2) |
2190                              _VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
2191                 IOMn(ui32Module)->MI2CCFG = _VAL2FLD(IOM0_MI2CCFG_STRDIS, 0)                            |
2192                                             _VAL2FLD(IOM0_MI2CCFG_SMPCNT, 3)                            |
2193                                             _VAL2FLD(IOM0_MI2CCFG_SDAENDLY, 15)                         |
2194                                             _VAL2FLD(IOM0_MI2CCFG_SCLENDLY, 2)                          |
2195                                             _VAL2FLD(IOM0_MI2CCFG_MI2CRST, 1)                           |
2196                                             _VAL2FLD(IOM0_MI2CCFG_SDADLY, 3)                            |
2197                                             _VAL2FLD(IOM0_MI2CCFG_ARBEN, IOM0_MI2CCFG_ARBEN_ARBDIS)     |
2198                                             _VAL2FLD(IOM0_MI2CCFG_I2CLSB, IOM0_MI2CCFG_I2CLSB_MSBFIRST) |
2199                                             _VAL2FLD(IOM0_MI2CCFG_ADDRSZ, IOM0_MI2CCFG_ADDRSZ_ADDRSZ7);
2200                 break;
2201             case AM_HAL_IOM_1MHZ:
2202                 //
2203                 // settings below should give ~860 kHz
2204                 //
2205                 ui32ClkCfg = _VAL2FLD(IOM0_CLKCFG_TOTPER, 0x06)                     |
2206                              _VAL2FLD(IOM0_CLKCFG_LOWPER, 0x03)                     |
2207                              _VAL2FLD(IOM0_CLKCFG_DIVEN, IOM0_CLKCFG_DIVEN_EN)      |
2208                              _VAL2FLD(IOM0_CLKCFG_DIV3, IOM0_CLKCFG_DIV3_DIS)       |
2209                              _VAL2FLD(IOM0_CLKCFG_FSEL, IOM0_CLKCFG_FSEL_HFRC_DIV4) |
2210                              _VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
2211                 IOMn(ui32Module)->MI2CCFG = _VAL2FLD(IOM0_MI2CCFG_STRDIS, 0)                            |
2212                                             _VAL2FLD(IOM0_MI2CCFG_SMPCNT, 0x21)                         |
2213                                             _VAL2FLD(IOM0_MI2CCFG_SDAENDLY, 3)                          |
2214                                             _VAL2FLD(IOM0_MI2CCFG_SCLENDLY, 0)                          |
2215                                             _VAL2FLD(IOM0_MI2CCFG_MI2CRST, 1)                           |
2216                                             _VAL2FLD(IOM0_MI2CCFG_SDADLY, 0)                            |
2217                                             _VAL2FLD(IOM0_MI2CCFG_ARBEN, IOM0_MI2CCFG_ARBEN_ARBDIS)     |
2218                                             _VAL2FLD(IOM0_MI2CCFG_I2CLSB, IOM0_MI2CCFG_I2CLSB_MSBFIRST) |
2219                                             _VAL2FLD(IOM0_MI2CCFG_ADDRSZ, IOM0_MI2CCFG_ADDRSZ_ADDRSZ7);
2220                 break;
2221             default:
2222                 return AM_HAL_STATUS_INVALID_ARG;
2223         }
2224     }
2225     else
2226     {
2227         return AM_HAL_STATUS_OUT_OF_RANGE;
2228     }
2229 
2230     //
2231     // Enable and set the clock configuration.
2232     //
2233     ui32ClkCfg |= _VAL2FLD(IOM0_CLKCFG_IOCLKEN, 1);
2234     IOMn(ui32Module)->CLKCFG = ui32ClkCfg;
2235 
2236     pIOMState->ui32BitTimeTicks = AM_HAL_CLKGEN_FREQ_MAX_HZ / psConfig->ui32ClockFreq;
2237 
2238     //
2239     // Set the delay timeout value to the default maximum value.
2240     //
2241     pIOMState->waitTimeout = 1000;
2242 
2243     pIOMState->pNBTxnBuf = psConfig->pNBTxnBuf;
2244     pIOMState->ui32NBTxnBufLength = psConfig->ui32NBTxnBufLength;
2245     // Worst case minimum CQ entries that can be accomodated in provided buffer
2246     // Need to account for the wrap
2247     pIOMState->ui32MaxPending = ((pIOMState->ui32NBTxnBufLength - 8) * 4 / AM_HAL_IOM_CQ_ENTRY_SIZE);
2248     if (pIOMState->ui32MaxPending > AM_HAL_IOM_MAX_PENDING_TRANSACTIONS)
2249     {
2250         pIOMState->ui32MaxPending = AM_HAL_IOM_MAX_PENDING_TRANSACTIONS;
2251     }
2252     // Disable the DCX
2253     for (uint8_t i = 0; i <= AM_HAL_IOM_MAX_CS_SPI; i++)
2254     {
2255         pIOMState->dcx[i] = 0;
2256     }
2257 
2258     //
2259     // Return the status.
2260     //
2261     return status;
2262 
2263 } // am_hal_iom_configure()
2264 
2265 //*****************************************************************************
2266 //
2267 // IOM blocking transfer function
2268 //
2269 //*****************************************************************************
2270 uint32_t
am_hal_iom_blocking_transfer(void * pHandle,am_hal_iom_transfer_t * psTransaction)2271 am_hal_iom_blocking_transfer(void *pHandle,
2272                              am_hal_iom_transfer_t *psTransaction)
2273 {
2274     uint32_t ui32Cmd, ui32Offset, ui32OffsetCnt, ui32Dir, ui32Cont;
2275     uint32_t ui32FifoRem, ui32FifoSiz;
2276     uint32_t ui32Bytes;
2277     uint32_t ui32IntConfig;
2278     uint32_t *pui32Buffer;
2279     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
2280     uint32_t ui32Module;
2281     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
2282     bool     bCmdCmp = false;
2283     uint32_t numWait = 0;
2284 
2285 #ifndef AM_HAL_DISABLE_API_VALIDATION
2286     if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
2287     {
2288         return AM_HAL_STATUS_INVALID_HANDLE;
2289     }
2290 
2291     if ( !psTransaction )
2292     {
2293         return AM_HAL_STATUS_INVALID_ARG;
2294     }
2295 
2296     if (psTransaction->eDirection > AM_HAL_IOM_RX)
2297     {
2298         return AM_HAL_STATUS_INVALID_OPERATION;
2299     }
2300 #endif // AM_HAL_DISABLE_API_VALIDATION
2301 
2302     ui32Bytes = psTransaction->ui32NumBytes;
2303     if ( ui32Bytes == 0 )
2304     {
2305         //
2306         // Only TX is supported for 0-length transactions. A 0-length
2307         // transfer presumes that only an offset value is being written.
2308         //
2309         psTransaction->eDirection = AM_HAL_IOM_TX;
2310     }
2311 
2312 #ifndef AM_HAL_DISABLE_API_VALIDATION
2313     //
2314     // Validate parameters
2315     //
2316     ui32Status = validate_transaction(pIOMState, psTransaction, true);
2317 
2318     if (ui32Status != AM_HAL_STATUS_SUCCESS)
2319     {
2320         return ui32Status;
2321     }
2322 #endif // AM_HAL_DISABLE_API_VALIDATION
2323     if (pIOMState->eSeq == AM_HAL_IOM_SEQ_RUNNING)
2324     {
2325         // Dynamic additions to sequence not allowed
2326         return AM_HAL_STATUS_INVALID_OPERATION;
2327     }
2328 
2329     ui32Module = pIOMState->ui32Module;
2330     ui32Offset = psTransaction->ui32Instr;
2331     ui32OffsetCnt = psTransaction->ui32InstrLen;
2332     ui32Dir = psTransaction->eDirection;
2333     ui32Cont = psTransaction->bContinue ? 1 : 0;
2334     pui32Buffer = (ui32Dir == AM_HAL_IOM_TX) ? psTransaction->pui32TxBuffer : psTransaction->pui32RxBuffer;
2335 
2336     //
2337     // Make sure any previous non-blocking transfers have completed.
2338     //
2339     ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
2340                                                  (uint32_t)&pIOMState->ui32NumPendTransactions,
2341                                                  0xFFFFFFFF,
2342                                                  0,
2343                                                  true);
2344     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
2345     {
2346         return ui32Status;
2347     }
2348 
2349     //
2350     // Make sure any previous blocking transfer has been completed.
2351     // This check is required to make sure previous transaction has cleared if the blocking call
2352     // finished with a timeout
2353     //
2354     ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
2355                             (uint32_t)&IOMn(ui32Module)->STATUS,
2356                             (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
2357                             IOM0_STATUS_IDLEST_Msk,
2358                             true);
2359 
2360     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
2361     {
2362         return ui32Status;
2363     }
2364 
2365     //
2366     // Disable interrupts so that we don't get any undesired interrupts.
2367     //
2368     ui32IntConfig = IOMn(ui32Module)->INTEN;
2369     //
2370     // Disable IOM interrupts as we'll be polling
2371     //
2372     IOMn(ui32Module)->INTEN = 0;
2373     //
2374     // Disable DMA - in case the last transaction was DMA
2375     // For CQ - we disable DMA only at the start of next transaction
2376     //
2377     IOMn(ui32Module)->DMACFG_b.DMAEN = 0;
2378 
2379 
2380     //
2381     // Clear interrupts
2382     //
2383     IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
2384 
2385     //
2386     // Set the dev addr (either 7 or 10 bit as configured in MI2CCFG).
2387     //
2388     IOMn(ui32Module)->DEVCFG = psTransaction->uPeerInfo.ui32I2CDevAddr;
2389     // CMDRPT register has been repurposed for DCX
2390     // Set the DCX
2391     IOMn(ui32Module)->DCX = (pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE)  ? pIOMState->dcx[psTransaction->uPeerInfo.ui32SpiChipSelect] : 0;
2392     //
2393     // Build the CMD value
2394     //
2395 
2396     ui32Cmd = pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE ?
2397               psTransaction->uPeerInfo.ui32SpiChipSelect : 0;
2398     ui32Cmd = build_cmd(ui32Cmd, ui32Dir,  ui32Cont, ui32Offset, ui32OffsetCnt, ui32Bytes);
2399 
2400     //
2401     // Set the OFFSETHI register.
2402     //
2403     IOMn(ui32Module)->OFFSETHI = (uint16_t)(ui32Offset >> 8);
2404 
2405     ui32Bytes = psTransaction->ui32NumBytes;
2406 
2407     if ( ui32Dir == AM_HAL_IOM_RX )
2408     {
2409         //
2410         // Start the transfer
2411         //
2412         IOMn(ui32Module)->CMD = ui32Cmd;
2413 
2414 
2415         //
2416         // Start a loop to catch the Rx data.
2417         //
2418         while ( ui32Bytes )
2419         {
2420             //
2421             // Limit the wait to reasonable limit - instead of blocking forever
2422             //
2423             numWait = 0;
2424             while ((ui32FifoSiz = IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ) < 4)
2425             {
2426                 if (numWait++ < AM_HAL_IOM_MAX_BLOCKING_WAIT)
2427                 {
2428                     if (bCmdCmp && (ui32Bytes > ui32FifoSiz))
2429                     {
2430                         //
2431                         // No more data expected. Get out of the loop
2432                         //
2433                         break;
2434                     }
2435                     am_hal_flash_delay( FLASH_CYCLES_US(1) );
2436                 }
2437                 else
2438                 {
2439                     //
2440                     // We've waited long enough - get out!
2441                     //
2442                     break;
2443                 }
2444                 bCmdCmp = IOMn(ui32Module)->INTSTAT_b.CMDCMP;
2445             }
2446             if (ui32FifoSiz < 4)
2447             {
2448                 //
2449                 // Something went wrong - get out and report failure
2450                 //
2451                 break;
2452             }
2453 
2454             while ((ui32FifoSiz >= 4) && ui32Bytes)
2455             {
2456                 //
2457                 // Safe to read the FIFO, read 4 bytes
2458                 //
2459                 uint32_t ui32Read;
2460                 ui32Read = IOMn(ui32Module)->FIFOPOP;
2461 #if MANUAL_POP
2462                 IOMn(ui32Module)->FIFOPOP = 0x11111111;
2463 #endif
2464                 ui32FifoSiz -= 4;
2465                 if (ui32Bytes >= 4)
2466                 {
2467                     *pui32Buffer++ = ui32Read;
2468                     ui32Bytes -= 4;
2469                 }
2470                 else
2471                 {
2472                     // Copy byte by byte - so as to not corrupt the rest of the buffer
2473                     uint8_t *pui8Buffer = (uint8_t *)pui32Buffer;
2474                     do
2475                     {
2476                         *pui8Buffer++ = ui32Read & 0xFF;
2477                         ui32Read >>= 8;
2478                     } while (--ui32Bytes);
2479 
2480                 }
2481             }
2482         }
2483     }
2484     else if ( ui32Dir == AM_HAL_IOM_TX )
2485     {
2486         // Write data to FIFO first - before starting the transfer
2487 
2488         ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM;
2489         while ((ui32FifoRem >= 4) && ui32Bytes)
2490         {
2491             IOMn(ui32Module)->FIFOPUSH = *pui32Buffer++;
2492             ui32FifoRem -= 4;
2493             if (ui32Bytes >= 4)
2494             {
2495                 ui32Bytes -= 4;
2496             }
2497             else
2498             {
2499                 ui32Bytes = 0;
2500             }
2501         }
2502 
2503         //
2504         // Start the transfer
2505         //
2506         IOMn(ui32Module)->CMD = ui32Cmd;
2507         //
2508         // Keep looping until we're out of bytes to send or command complete (error).
2509         //
2510         while (ui32Bytes)
2511         {
2512             //
2513             // Limit the wait to reasonable limit - instead of blocking forever
2514             //
2515             numWait = 0;
2516             while ((ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM) < 4)
2517             {
2518                 bCmdCmp = IOMn(ui32Module)->INTSTAT_b.CMDCMP;
2519                 if (bCmdCmp || (numWait++ >= AM_HAL_IOM_MAX_BLOCKING_WAIT))
2520                 {
2521                     //
2522                     // FIFO not expected to change any more - get out
2523                     //
2524                     break;
2525                 }
2526                 else
2527                 {
2528                     am_hal_flash_delay( FLASH_CYCLES_US(1) );
2529                 }
2530             }
2531             if (bCmdCmp || (ui32FifoRem < 4))
2532             {
2533                 //
2534                 // Something went wrong - bail out
2535                 //
2536                 break;
2537             }
2538 
2539             while ((ui32FifoRem >= 4) && ui32Bytes)
2540             {
2541                 IOMn(ui32Module)->FIFOPUSH = *pui32Buffer++;
2542                 ui32FifoRem -= 4;
2543                 if (ui32Bytes >= 4)
2544                 {
2545                     ui32Bytes -= 4;
2546                 }
2547                 else
2548                 {
2549                     ui32Bytes = 0;
2550                 }
2551             }
2552         }
2553     }
2554 
2555     //
2556     // Make sure transfer is completed.
2557     //
2558     ui32Status = am_hal_flash_delay_status_check(AM_HAL_IOM_MAX_BLOCKING_WAIT,
2559                             (uint32_t)&IOMn(ui32Module)->STATUS,
2560                             (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
2561                             IOM0_STATUS_IDLEST_Msk,
2562                             true);
2563 
2564     if ( ui32Status == AM_HAL_STATUS_SUCCESS )
2565     {
2566         ui32Status = internal_iom_get_int_err(ui32Module, 0);
2567 
2568         if (ui32Status == AM_HAL_STATUS_SUCCESS)
2569         {
2570             if (ui32Bytes)
2571             {
2572                 // Indicates transaction did not finish for some reason
2573                 ui32Status = AM_HAL_STATUS_FAIL;
2574             }
2575         }
2576     }
2577 
2578     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
2579     {
2580         // Do Error recovery
2581         // Reset Submodule & FIFO
2582         internal_iom_reset_on_error(pIOMState, IOMn(ui32Module)->INTSTAT);
2583     }
2584 
2585     //
2586     // Clear interrupts
2587     // Re-enable IOM interrupts.
2588     //
2589     IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
2590     IOMn(ui32Module)->INTEN = ui32IntConfig;
2591 
2592     //
2593     // Return the status.
2594     //
2595     return ui32Status;
2596 
2597 } // am_hal_iom_blocking_transfer()
2598 
2599 
2600 //*****************************************************************************
2601 //
2602 // IOM non-blocking transfer function
2603 //
2604 //*****************************************************************************
2605 uint32_t
am_hal_iom_nonblocking_transfer(void * pHandle,am_hal_iom_transfer_t * psTransaction,am_hal_iom_callback_t pfnCallback,void * pCallbackCtxt)2606 am_hal_iom_nonblocking_transfer(void *pHandle,
2607                                 am_hal_iom_transfer_t *psTransaction,
2608                                 am_hal_iom_callback_t pfnCallback,
2609                                 void *pCallbackCtxt)
2610 {
2611     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
2612     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
2613     uint32_t ui32NumPend;
2614 
2615 #ifndef AM_HAL_DISABLE_API_VALIDATION
2616     uint32_t    ui32DMAAddress;
2617 
2618     if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
2619     {
2620         return AM_HAL_STATUS_INVALID_HANDLE;
2621     }
2622 
2623     if ( !psTransaction )
2624     {
2625         return AM_HAL_STATUS_INVALID_ARG;
2626     }
2627 
2628     if (psTransaction->eDirection > AM_HAL_IOM_RX)
2629     {
2630         return AM_HAL_STATUS_INVALID_OPERATION;
2631     }
2632     //
2633     // Check for DMA to/from DTCM.
2634     //
2635     ui32DMAAddress = (psTransaction->eDirection == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
2636 
2637     if ( (ui32DMAAddress >= AM_HAL_FLASH_DTCM_START) &&
2638       (ui32DMAAddress <= AM_HAL_FLASH_DTCM_END) )
2639     {
2640       return AM_HAL_STATUS_OUT_OF_RANGE;
2641     }
2642 #endif // AM_HAL_DISABLE_API_VALIDATION
2643 
2644     if ( psTransaction->ui32NumBytes == 0 )
2645     {
2646         //
2647         // Only TX is supported for 0-length transactions. A 0-length
2648         // transfer presumes that only an offset value is being written.
2649         //
2650         psTransaction->eDirection = AM_HAL_IOM_TX;
2651     }
2652 
2653 #ifndef AM_HAL_DISABLE_API_VALIDATION
2654     //
2655     // Validate parameters
2656     //
2657     ui32Status = validate_transaction(pIOMState, psTransaction, false);
2658 
2659     if (ui32Status != AM_HAL_STATUS_SUCCESS)
2660     {
2661         return ui32Status;
2662     }
2663 #endif // AM_HAL_DISABLE_API_VALIDATION
2664 
2665 
2666     am_hal_iom_callback_t pfnCallback1 = pfnCallback;
2667     if (!pIOMState->pCmdQHdl)
2668     {
2669         return AM_HAL_STATUS_INVALID_OPERATION;
2670     }
2671     if (pIOMState->eSeq == AM_HAL_IOM_SEQ_RUNNING)
2672     {
2673         // Dynamic additions to sequence not allowed
2674         return AM_HAL_STATUS_INVALID_OPERATION;
2675     }
2676     if (pIOMState->block && (psTransaction->ui32PauseCondition != 0))
2677     {
2678         // Paused operations not allowed in block mode
2679         return AM_HAL_STATUS_INVALID_OPERATION;
2680     }
2681     if (!pfnCallback1 && !pIOMState->block && (pIOMState->eSeq == AM_HAL_IOM_SEQ_NONE) &&
2682         (pIOMState->ui32NumUnSolicited >= (pIOMState->ui32MaxPending / 2)))
2683     {
2684         // Need to schedule a dummy callback, to ensure ui32NumPendTransactions get updated in ISR
2685         pfnCallback1 = iom_dummy_callback;
2686     }
2687     //
2688     // DMA defaults to using the Command Queue
2689     //
2690     ui32Status = am_hal_iom_CQAddTransaction(pHandle, psTransaction, pfnCallback1, pCallbackCtxt);
2691 
2692     if (ui32Status == AM_HAL_STATUS_SUCCESS)
2693     {
2694         uint32_t ui32Critical = 0;
2695 
2696         //
2697         // Need to protect access of ui32NumPendTransactions as it is accessed
2698         // from ISR as well
2699         //
2700         // Start a critical section.
2701         //
2702         ui32Critical = am_hal_interrupt_master_disable();
2703 
2704         //
2705         // Register for interrupt only if there is a callback
2706         //
2707         ui32Status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, pfnCallback1);
2708         if (ui32Status == AM_HAL_STATUS_SUCCESS)
2709         {
2710             ui32NumPend = pIOMState->ui32NumPendTransactions++;
2711             pIOMState->ui32NumSeqTransactions++;
2712             if (pfnCallback)
2713             {
2714                 pIOMState->bAutonomous = false;
2715                 pIOMState->ui32NumUnSolicited = 0;
2716             }
2717             else
2718             {
2719                 if (pfnCallback1)
2720                 {
2721                     // This implies we have already scheduled a dummy callback
2722                     pIOMState->ui32NumUnSolicited = 0;
2723                 }
2724                 else
2725                 {
2726                     pIOMState->ui32NumUnSolicited++;
2727                 }
2728             }
2729             if (0 == ui32NumPend)
2730             {
2731                 pIOMState->ui32UserIntCfg = IOMn(pIOMState->ui32Module)->INTEN;
2732                 IOM_SET_INTEN(pIOMState->ui32Module, AM_HAL_IOM_INT_CQMODE);
2733                 am_hal_iom_CQEnable(pIOMState);
2734             }
2735 
2736         }
2737         else
2738         {
2739             am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
2740         }
2741         //
2742         // End the critical section.
2743         //
2744         am_hal_interrupt_master_set(ui32Critical);
2745     }
2746 
2747     //
2748     // Return the status.
2749     //
2750     return ui32Status;
2751 
2752 } // am_hal_iom_nonblocking_transfer()
2753 
2754 //*****************************************************************************
2755 //
2756 // @brief Perform a simple full-duplex transaction to the SPI interface.
2757 //
2758 // This function performs SPI full-duplex operation to a selected SPI device.
2759 //
2760 // @note The actual SPI and I2C interfaces operate in BYTES, not 32-bit words.
2761 // This means that you will need to byte-pack the \e pui32TxData array with the
2762 // data you intend to send over the interface. One easy way to do this is to
2763 // declare the array as a 32-bit integer array, but use an 8-bit pointer to
2764 // put your actual data into the array. If there are not enough bytes in your
2765 // desired message to completely fill the last 32-bit word, you may pad that
2766 // last word with bytes of any value. The IOM hardware will only read the
2767 // first \e ui32NumBytes in the \e pui32TxData array.
2768 //
2769 // @return returns AM_HAL_IOM_SUCCESS on successful execution.
2770 //
2771 //*****************************************************************************
2772 uint32_t
am_hal_iom_spi_blocking_fullduplex(void * pHandle,am_hal_iom_transfer_t * psTransaction)2773 am_hal_iom_spi_blocking_fullduplex(void *pHandle,
2774                                    am_hal_iom_transfer_t *psTransaction)
2775 {
2776     uint32_t ui32Cmd, ui32Offset, ui32OffsetCnt, ui32Dir, ui32Cont;
2777     uint32_t ui32FifoRem, ui32FifoSiz;
2778     uint32_t ui32Bytes;
2779     uint32_t ui32RxBytes;
2780     uint32_t ui32IntConfig;
2781     uint32_t *pui32TxBuffer;
2782     uint32_t *pui32RxBuffer;
2783     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
2784     uint32_t ui32Module;
2785     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
2786     bool     bCmdCmp = false;
2787     uint32_t numWait = 0;
2788 
2789 #ifndef AM_HAL_DISABLE_API_VALIDATION
2790     if ( !AM_HAL_IOM_CHK_HANDLE(pHandle) )
2791     {
2792         return AM_HAL_STATUS_INVALID_HANDLE;
2793     }
2794 
2795     if ( !psTransaction )
2796     {
2797         return AM_HAL_STATUS_INVALID_ARG;
2798     }
2799 
2800     if ( psTransaction->eDirection != AM_HAL_IOM_FULLDUPLEX )
2801     {
2802         return AM_HAL_STATUS_INVALID_OPERATION;
2803     }
2804 
2805     //
2806     // Validate parameters
2807     //
2808     ui32Status = validate_transaction(pIOMState, psTransaction, true);
2809 
2810     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
2811     {
2812         return ui32Status;
2813     }
2814 #endif // AM_HAL_DISABLE_API_VALIDATION
2815 
2816     ui32Module = pIOMState->ui32Module;
2817     ui32Offset = psTransaction->ui32Instr;
2818     ui32OffsetCnt = psTransaction->ui32InstrLen;
2819     ui32Bytes = psTransaction->ui32NumBytes;
2820     ui32Dir = psTransaction->eDirection;
2821     ui32Cont = psTransaction->bContinue ? 1 : 0;
2822     pui32RxBuffer = psTransaction->pui32RxBuffer;
2823     pui32TxBuffer = psTransaction->pui32TxBuffer;
2824 
2825     //
2826     // Make sure any previous non-blocking transfers have completed.
2827     //
2828     ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
2829                                                  (uint32_t)&pIOMState->ui32NumPendTransactions,
2830                                                  0xFFFFFFFF,
2831                                                  0,
2832                                                  true);
2833     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
2834     {
2835         return ui32Status;
2836     }
2837 
2838     //
2839     // Make sure any previous blocking transfer has been completed.
2840     // This check is required to make sure previous transaction has cleared if the blocking call
2841     // finished with a timeout
2842     //
2843     ui32Status = am_hal_flash_delay_status_check(pIOMState->waitTimeout,
2844                             (uint32_t)&IOMn(ui32Module)->STATUS,
2845                             (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
2846                             IOM0_STATUS_IDLEST_Msk,
2847                             true);
2848 
2849     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
2850     {
2851         return ui32Status;
2852     }
2853 
2854     //
2855     // Disable interrupts so that we don't get any undesired interrupts.
2856     //
2857     ui32IntConfig = IOMn(ui32Module)->INTEN;
2858 
2859     //
2860     // Disable IOM interrupts as we'll be polling
2861     //
2862     IOMn(ui32Module)->INTEN = 0;
2863 
2864     //
2865     // Clear interrupts
2866     //
2867     IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
2868 
2869     //
2870     // Set the dev addr (either 7 or 10 bit as configured in MI2CCFG).
2871     //
2872     IOMn(ui32Module)->DEVCFG = psTransaction->uPeerInfo.ui32I2CDevAddr;
2873     // CMDRPT register has been repurposed for DCX
2874     // Set the DCX
2875     IOMn(ui32Module)->DCX = pIOMState->dcx[psTransaction->uPeerInfo.ui32SpiChipSelect];
2876 
2877     //
2878     // Build the CMD value
2879     //
2880 
2881     ui32Cmd = pIOMState->eInterfaceMode == AM_HAL_IOM_SPI_MODE ?
2882               psTransaction->uPeerInfo.ui32SpiChipSelect : 0;
2883     ui32Cmd = build_cmd(ui32Cmd, ui32Dir,  ui32Cont, ui32Offset, ui32OffsetCnt, ui32Bytes);
2884 
2885     //
2886     // Set the OFFSETHI register.
2887     //
2888     IOMn(ui32Module)->OFFSETHI = (uint16_t)(ui32Offset >> 8);
2889 
2890     //
2891     // Set FULLDUPLEX mode
2892     //
2893     IOMn(ui32Module)->MSPICFG |= _VAL2FLD(IOM0_MSPICFG_FULLDUP, 1);
2894 
2895     //
2896     // Start the transfer
2897     //
2898     IOMn(ui32Module)->CMD = ui32Cmd;
2899 
2900     ui32Bytes = psTransaction->ui32NumBytes;
2901     ui32RxBytes = ui32Bytes;
2902 
2903     //
2904     // Start a loop to catch the Rx data.
2905     //
2906     //
2907     // Keep looping until we're out of bytes to send or command complete (error).
2908     //
2909     while (!bCmdCmp && (ui32Bytes || ui32RxBytes))
2910     {
2911         //
2912         // Limit the wait to reasonable limit - instead of blocking forever
2913         //
2914         numWait = 0;
2915         ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM;
2916         ui32FifoSiz = IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ;
2917 
2918         while ((ui32FifoRem < 4) &&
2919                (ui32FifoSiz < 4))
2920         {
2921             if (numWait++ < AM_HAL_IOM_MAX_BLOCKING_WAIT)
2922             {
2923                 if (bCmdCmp && (ui32RxBytes > ui32FifoSiz))
2924                 {
2925                     //
2926                     // No more data expected. Get out of the loop
2927                     //
2928                     break;
2929                 }
2930                 am_hal_flash_delay( FLASH_CYCLES_US(1) );
2931             }
2932             else
2933             {
2934                 //
2935                 // We've waited long enough - get out!
2936                 //
2937                 break;
2938             }
2939             bCmdCmp     = IOMn(ui32Module)->INTSTAT_b.CMDCMP;
2940             ui32FifoRem = IOMn(ui32Module)->FIFOPTR_b.FIFO0REM;
2941             ui32FifoSiz = IOMn(ui32Module)->FIFOPTR_b.FIFO1SIZ;
2942         }
2943         if ((ui32FifoRem < 4) && (ui32FifoSiz < 4))
2944         {
2945             //
2946             // Something went wrong - bail out
2947             //
2948             break;
2949         }
2950 
2951         while ((ui32FifoRem >= 4) && ui32Bytes)
2952         {
2953             IOMn(ui32Module)->FIFOPUSH = *pui32TxBuffer++;
2954             ui32FifoRem -= 4;
2955             if (ui32Bytes >= 4)
2956             {
2957                 ui32Bytes -= 4;
2958             }
2959             else
2960             {
2961                 ui32Bytes = 0;
2962             }
2963         }
2964         while ((ui32FifoSiz >= 4) && ui32RxBytes)
2965         {
2966             //
2967             // Safe to read the FIFO, read 4 bytes
2968             //
2969             uint32_t ui32Read;
2970             ui32Read = IOMn(ui32Module)->FIFOPOP;
2971 #if MANUAL_POP
2972             IOMn(ui32Module)->FIFOPOP = 0x11111111;
2973 #endif
2974             ui32FifoSiz -= 4;
2975             if (ui32RxBytes >= 4)
2976             {
2977                 *pui32RxBuffer++ = ui32Read;
2978                 ui32RxBytes -= 4;
2979             }
2980             else
2981             {
2982                 // Copy byte by byte - so as to not corrupt the rest of the buffer
2983                 uint8_t *pui8Buffer = (uint8_t *)pui32RxBuffer;
2984                 do
2985                 {
2986                     *pui8Buffer++ = ui32Read & 0xFF;
2987                     ui32Read >>= 8;
2988                 } while (--ui32RxBytes);
2989 
2990             }
2991         }
2992     }
2993 
2994     //
2995     // Make sure transfer is completed.
2996     //
2997     ui32Status = am_hal_flash_delay_status_check(AM_HAL_IOM_MAX_BLOCKING_WAIT,
2998                             (uint32_t)&IOMn(ui32Module)->STATUS,
2999                             (IOM0_STATUS_IDLEST_Msk | IOM0_STATUS_CMDACT_Msk),
3000                             IOM0_STATUS_IDLEST_Msk,
3001                             true);
3002 
3003     if ( ui32Status == AM_HAL_STATUS_SUCCESS )
3004     {
3005         ui32Status = internal_iom_get_int_err(ui32Module, 0);
3006 
3007         if (ui32Status == AM_HAL_STATUS_SUCCESS)
3008         {
3009             if (ui32Bytes || ui32RxBytes)
3010             {
3011                 // Indicates transaction did not finish for some reason
3012                 ui32Status = AM_HAL_STATUS_FAIL;
3013             }
3014         }
3015     }
3016 
3017     if ( ui32Status != AM_HAL_STATUS_SUCCESS )
3018     {
3019         // Do Error recovery
3020         // Reset Submodule & FIFO
3021         internal_iom_reset_on_error(pIOMState, IOMn(ui32Module)->INTSTAT);
3022     }
3023 
3024     //
3025     // Revert FULLDUPLEX mode
3026     //
3027     IOMn(ui32Module)->MSPICFG &= ~_VAL2FLD(IOM0_MSPICFG_FULLDUP, 1);
3028     //
3029     // Clear interrupts
3030     // Re-enable IOM interrupts.
3031     //
3032     IOMn(ui32Module)->INTCLR = AM_HAL_IOM_INT_ALL;
3033     IOMn(ui32Module)->INTEN = ui32IntConfig;
3034 
3035     //
3036     // Return the status.
3037     //
3038     return ui32Status;
3039 
3040 }
3041 
3042 //*****************************************************************************
3043 //
3044 // @brief IOM control function
3045 //
3046 // @param pHandle       - handle for the IOM.
3047 // @param eReq         - device specific special request code.
3048 // @param pArgs        - pointer to the request specific arguments.
3049 //
3050 // This function allows advanced settings
3051 //
3052 // @return status      - generic or interface specific status.
3053 //
3054 //*****************************************************************************
am_hal_iom_control(void * pHandle,am_hal_iom_request_e eReq,void * pArgs)3055 uint32_t am_hal_iom_control(void *pHandle, am_hal_iom_request_e eReq, void *pArgs)
3056 {
3057     am_hal_iom_state_t *pIOMState = (am_hal_iom_state_t*)pHandle;
3058     uint32_t status = AM_HAL_STATUS_SUCCESS;
3059 
3060 #ifndef AM_HAL_DISABLE_API_VALIDATION
3061     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
3062     {
3063         return AM_HAL_STATUS_INVALID_HANDLE;
3064     }
3065 
3066     //
3067     // Validate the parameters
3068     //
3069     if (eReq >= AM_HAL_IOM_REQ_MAX)
3070     {
3071         return AM_HAL_STATUS_INVALID_ARG;
3072     }
3073 #endif // AM_HAL_DISABLE_API_VALIDATION
3074 
3075     uint32_t ui32Module = pIOMState->ui32Module;
3076     switch (eReq)
3077     {
3078         case AM_HAL_IOM_REQ_FLAG_SETCLR:
3079             if (pArgs)
3080             {
3081 #ifndef AM_HAL_DISABLE_API_VALIDATION
3082                 if (*((uint32_t *)pArgs) & AM_HAL_IOM_SC_RESV_MASK)
3083                 {
3084                     return AM_HAL_STATUS_INVALID_ARG;
3085                 }
3086 #endif // AM_HAL_DISABLE_API_VALIDATION
3087                 IOMn(ui32Module)->CQSETCLEAR = *((uint32_t *)pArgs);
3088             }
3089             else
3090             {
3091                 status = AM_HAL_STATUS_INVALID_ARG;
3092             }
3093             break;
3094         case AM_HAL_IOM_REQ_SPI_LSB:
3095             if (pArgs)
3096             {
3097                 IOMn(ui32Module)->MSPICFG_b.SPILSB = *((uint32_t *)pArgs);
3098             }
3099             else
3100             {
3101                 status = AM_HAL_STATUS_INVALID_ARG;
3102             }
3103             break;
3104         case AM_HAL_IOM_REQ_SPI_RDTHRESH:
3105             if (pArgs)
3106             {
3107                 IOMn(ui32Module)->FIFOTHR_b.FIFORTHR = *((uint32_t *)pArgs);
3108             }
3109             else
3110             {
3111                 status = AM_HAL_STATUS_INVALID_ARG;
3112             }
3113             break;
3114         case AM_HAL_IOM_REQ_SPI_WRTHRESH:
3115             if (pArgs)
3116             {
3117                 IOMn(ui32Module)->FIFOTHR_b.FIFOWTHR = *((uint32_t *)pArgs);
3118             }
3119             else
3120             {
3121                 status = AM_HAL_STATUS_INVALID_ARG;
3122             }
3123             break;
3124 
3125     case AM_HAL_IOM_REQ_LINK_MSPI:
3126             if (pArgs)
3127             {
3128 #ifndef AM_HAL_DISABLE_API_VALIDATION
3129                 if (*((uint32_t *)pArgs) > AM_REG_MSPI_NUM_MODULES)
3130                 {
3131                     return AM_HAL_STATUS_INVALID_ARG;
3132                 }
3133 #endif // AM_HAL_DISABLE_API_VALIDATION
3134                 IOMn(ui32Module)->CQCFG_b.MSPIFLGSEL = *((uint32_t *)pArgs);
3135             }
3136             else
3137             {
3138                 status = AM_HAL_STATUS_INVALID_ARG;
3139             }
3140             break;
3141     case AM_HAL_IOM_REQ_PAUSE:
3142             // Force CQ to Paused
3143             status = iom_cq_pause(pIOMState);
3144             break;
3145 
3146         case AM_HAL_IOM_REQ_UNPAUSE:
3147             // Resume the CQ
3148             IOMn(ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_CQ;
3149             break;
3150 
3151 
3152         case AM_HAL_IOM_REQ_SET_SEQMODE:
3153         {
3154             am_hal_iom_seq_e eSeq;
3155 #ifndef AM_HAL_DISABLE_API_VALIDATION
3156             if (!pArgs)
3157             {
3158                 return AM_HAL_STATUS_INVALID_ARG;
3159             }
3160             if (!pIOMState->pNBTxnBuf)
3161             {
3162                 // No space for CMDQ
3163                 return AM_HAL_STATUS_INVALID_OPERATION;
3164             }
3165 #endif // AM_HAL_DISABLE_API_VALIDATION
3166             eSeq = *((bool *)pArgs) ? AM_HAL_IOM_SEQ_UNDER_CONSTRUCTION: AM_HAL_IOM_SEQ_NONE;
3167             if (eSeq == pIOMState->eSeq)
3168             {
3169                 // Nothing to do
3170                 return AM_HAL_STATUS_SUCCESS;
3171             }
3172 
3173             switch (pIOMState->eSeq)
3174             {
3175                 case AM_HAL_IOM_SEQ_RUNNING:
3176                 {
3177                     // Force CQ to Pause
3178                     status = iom_cq_pause(pIOMState);
3179                     break;
3180                 }
3181                 case AM_HAL_IOM_SEQ_NONE:
3182                 {
3183                     // Make sure there is no non-blocking transaction in progress
3184                     if (pIOMState->ui32NumPendTransactions)
3185                     {
3186                         status = AM_HAL_STATUS_INVALID_OPERATION;
3187                     }
3188                     break;
3189                 }
3190                 default:
3191                     ;
3192             }
3193             if (status == AM_HAL_STATUS_SUCCESS)
3194             {
3195                 // Reset the cmdq
3196                 am_hal_cmdq_reset(pIOMState->pCmdQHdl);
3197                 pIOMState->ui32LastIdxProcessed = 0;
3198                 pIOMState->ui32NumSeqTransactions = 0;
3199                 pIOMState->ui32NumPendTransactions = 0;
3200                 pIOMState->ui32NumUnSolicited = 0;
3201                 pIOMState->eSeq = eSeq;
3202                 pIOMState->bAutonomous = true;
3203             }
3204             break;
3205         }
3206 
3207         case AM_HAL_IOM_REQ_SEQ_END:
3208         {
3209             uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
3210             am_hal_cmdq_entry_t     *pCQBlock;
3211             uint32_t                index;
3212             am_hal_iom_seq_end_t *pLoop = (am_hal_iom_seq_end_t *)pArgs;
3213             uint32_t pause = 0;
3214             uint32_t scUnpause = 0;
3215             uint32_t ui32Critical = 0;
3216 #ifndef AM_HAL_DISABLE_API_VALIDATION
3217             if (!pArgs)
3218             {
3219                 return AM_HAL_STATUS_INVALID_ARG;
3220             }
3221             if (pLoop->ui32PauseCondition & AM_HAL_IOM_PAUSE_FLAG_RESV)
3222             {
3223                 return AM_HAL_STATUS_INVALID_ARG;
3224             }
3225             if (pLoop->ui32StatusSetClr & AM_HAL_IOM_SC_RESV_MASK)
3226             {
3227                 return AM_HAL_STATUS_INVALID_ARG;
3228             }
3229             if (pIOMState->eSeq != AM_HAL_IOM_SEQ_UNDER_CONSTRUCTION)
3230             {
3231                 return AM_HAL_STATUS_INVALID_OPERATION;
3232             }
3233 #endif // AM_HAL_DISABLE_API_VALIDATION
3234             if (pIOMState->block)
3235             {
3236                 // End the block if the sequence is ending
3237                 pIOMState->block = 0;
3238                 // Unblock the whole batch of commands in this block
3239                 IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_BLOCK;
3240             }
3241 
3242             if ((pLoop->bLoop) && (!pIOMState->bAutonomous))
3243             {
3244                 // Need to insert special element in CQ to cause a callback
3245                 // This is to reset internal state
3246                 ui32Status = am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, 1, &pCQBlock, &index);
3247                 if (ui32Status != AM_HAL_STATUS_SUCCESS)
3248                 {
3249                     return ui32Status;
3250                 }
3251                 else
3252                 {
3253                     //
3254                     // Store the callback function pointer.
3255                     //
3256                     pIOMState->pfnCallback[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = iom_seq_loopback;
3257                     pIOMState->pCallbackCtxt[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = (void *)pIOMState;
3258 
3259                     // Dummy Entry
3260                     pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQSETCLEAR;
3261                     pCQBlock->value = 0;
3262                     //
3263                     // Need to protect access of ui32NumPendTransactions as it is accessed
3264                     // from ISR as well
3265                     //
3266                     // Start a critical section.
3267                     //
3268                     ui32Critical = am_hal_interrupt_master_disable();
3269 
3270                     //
3271                     // Post to the CQ.
3272                     //
3273                     ui32Status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, true);
3274 
3275                     if (AM_HAL_STATUS_SUCCESS != ui32Status)
3276                     {
3277                         am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
3278                     }
3279                     else
3280                     {
3281                         uint32_t ui32NumPend = pIOMState->ui32NumPendTransactions++;
3282                         if (0 == ui32NumPend)
3283                         {
3284                             pIOMState->ui32UserIntCfg = IOMn(ui32Module)->INTEN;
3285                             IOM_SET_INTEN(ui32Module, AM_HAL_IOM_INT_CQMODE);
3286                             // Re-enable the CQ
3287                             am_hal_iom_CQEnable(pIOMState);
3288                         }
3289                     }
3290                     //
3291                     // End the critical section.
3292                     //
3293                     am_hal_interrupt_master_set(ui32Critical);
3294                     // Use SWFLAG6 to cause a pause
3295                     pause = AM_HAL_IOM_PAUSE_FLAG_SEQLOOP;
3296                     // Revert back the flag after SW callback unpauses it
3297                     scUnpause = AM_HAL_IOM_SC_PAUSE_SEQLOOP;
3298                 }
3299             }
3300 
3301             // Insert the loopback
3302             ui32Status = am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, sizeof(am_hal_iom_cq_loop_entry_t) / 8, &pCQBlock, &index);
3303             if (ui32Status != AM_HAL_STATUS_SUCCESS)
3304             {
3305                 return ui32Status;
3306             }
3307             else
3308             {
3309                 am_hal_iom_cq_loop_entry_t *pLoopEntry = (am_hal_iom_cq_loop_entry_t *)pCQBlock;
3310                 pLoopEntry->ui32PAUSENAddr = pLoopEntry->ui32PAUSEN2Addr = (uint32_t)&IOMn(ui32Module)->CQPAUSEEN;
3311                 pLoopEntry->ui32SETCLRAddr = (uint32_t)&IOMn(ui32Module)->CQSETCLEAR;
3312                 pLoopEntry->ui32PAUSEENVal = get_pause_val(pIOMState, pLoop->ui32PauseCondition | pause);
3313                 pLoopEntry->ui32PAUSEEN2Val = AM_HAL_IOM_PAUSE_DEFAULT;
3314                 pLoopEntry->ui32SETCLRVal = pLoop->ui32StatusSetClr | scUnpause;
3315 
3316 
3317                 //
3318                 // Need to protect access of ui32NumPendTransactions as it is accessed
3319                 // from ISR as well
3320                 //
3321                 // Start a critical section.
3322                 //
3323                 ui32Critical = am_hal_interrupt_master_disable();
3324 
3325                 //
3326                 // Post to the CQ.
3327                 //
3328                 if (pLoop->bLoop)
3329                 {
3330                     ui32Status = am_hal_cmdq_post_loop_block(pIOMState->pCmdQHdl, false);
3331                 }
3332                 else
3333                 {
3334                     ui32Status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, false);
3335                 }
3336 
3337                 if (AM_HAL_STATUS_SUCCESS != ui32Status)
3338                 {
3339                     am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
3340                 }
3341                 else
3342                 {
3343                     uint32_t ui32NumPend = pIOMState->ui32NumPendTransactions++;
3344                     pIOMState->eSeq = (pLoop->bLoop) ? AM_HAL_IOM_SEQ_RUNNING : AM_HAL_IOM_SEQ_NONE;
3345                     if (0 == ui32NumPend)
3346                     {
3347                         pIOMState->ui32UserIntCfg = IOMn(ui32Module)->INTEN;
3348                         IOM_SET_INTEN(ui32Module, AM_HAL_IOM_INT_CQMODE);
3349                         // Re-enable the CQ
3350                         am_hal_iom_CQEnable(pIOMState);
3351                     }
3352                 }
3353                 //
3354                 // End the critical section.
3355                 //
3356                 am_hal_interrupt_master_set(ui32Critical);
3357             }
3358             return AM_HAL_STATUS_SUCCESS;
3359             //break;
3360         }
3361         case AM_HAL_IOM_REQ_INIT_HIPRIO:
3362         {
3363             am_hal_iom_hiprio_cfg_t *pHPCfg = (am_hal_iom_hiprio_cfg_t *)pArgs;
3364 #ifndef AM_HAL_DISABLE_API_VALIDATION
3365             if (!pHPCfg)
3366             {
3367                 return AM_HAL_STATUS_INVALID_ARG;
3368             }
3369 #endif // AM_HAL_DISABLE_API_VALIDATION
3370             pIOMState->ui32NumHPEntries = pIOMState->ui32LastHPIdxProcessed = 0;
3371             pIOMState->ui32NextHPIdx = pIOMState->ui32LastHPIdxProcessed + 1;
3372             pIOMState->pHPTransactions = (am_hal_iom_dma_entry_t *)pHPCfg->pBuf;
3373             pIOMState->ui32MaxHPTransactions = pHPCfg->size / sizeof(am_hal_iom_dma_entry_t);
3374             break;
3375         }
3376 
3377         case AM_HAL_IOM_REQ_START_BLOCK:
3378             // Pause the next block from proceeding till whole block is finished
3379             IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_PAUSE_BLOCK;
3380             pIOMState->block = 1;
3381             pIOMState->ui32NumHPPendingEntries = 0;
3382             break;
3383 
3384         case AM_HAL_IOM_REQ_END_BLOCK:
3385             // Unblock the whole batch of commands in this block
3386             IOMn(pIOMState->ui32Module)->CQSETCLEAR = AM_HAL_IOM_SC_UNPAUSE_BLOCK;
3387             pIOMState->block = 0;
3388             if (pIOMState->ui32NumHPPendingEntries)
3389             {
3390                 // Now it is okay to let go of the block of HiPrio transactions
3391                 status = sched_hiprio(pIOMState, pIOMState->ui32NumHPPendingEntries);
3392                 if (status == AM_HAL_STATUS_SUCCESS)
3393                 {
3394                     pIOMState->ui32NumHPPendingEntries = 0;
3395                 }
3396             }
3397             break;
3398 
3399         case AM_HAL_IOM_REQ_SET_DCX:
3400         {
3401             am_hal_iom_dcx_cfg_t *pDcxCfg = (am_hal_iom_dcx_cfg_t *)pArgs;
3402 #ifndef AM_HAL_DISABLE_API_VALIDATION
3403             if (!pDcxCfg)
3404             {
3405                 return AM_HAL_STATUS_INVALID_ARG;
3406             }
3407             if ((pIOMState->eInterfaceMode != AM_HAL_IOM_SPI_MODE) ||
3408                   (pDcxCfg->cs == pDcxCfg->dcx) ||
3409                   (pDcxCfg->cs > AM_HAL_IOM_MAX_CS_SPI) ||
3410                   ((pDcxCfg->dcx != AM_HAL_IOM_DCX_INVALID) && (pDcxCfg->dcx > AM_HAL_IOM_MAX_CS_SPI)))
3411             {
3412                 return AM_HAL_STATUS_INVALID_ARG;
3413             }
3414 #endif // AM_HAL_DISABLE_API_VALIDATION
3415             if ( !APOLLO3_GE_B0 )
3416             {
3417                 return AM_HAL_STATUS_INVALID_OPERATION;
3418             }
3419 
3420             pIOMState->dcx[pDcxCfg->cs] = (pDcxCfg->dcx == AM_HAL_IOM_DCX_INVALID) ? 0 : (IOM0_DCX_DCXEN_Msk | (0x1 << pDcxCfg->dcx));
3421             break;
3422         }
3423 
3424         case AM_HAL_IOM_REQ_CQ_RAW:
3425         {
3426             am_hal_iom_cq_raw_t *pCqRaw = (am_hal_iom_cq_raw_t *)pArgs;
3427             am_hal_cmdq_entry_t *pCQBlock;
3428             am_hal_iom_callback_t pfnCallback1;
3429 
3430             uint32_t            ui32Critical = 0;
3431             uint32_t            index;
3432 #ifndef AM_HAL_DISABLE_API_VALIDATION
3433             if (!pCqRaw)
3434             {
3435                 return AM_HAL_STATUS_INVALID_ARG;
3436             }
3437             if (!pIOMState->pCmdQHdl)
3438             {
3439                 return AM_HAL_STATUS_INVALID_OPERATION;
3440             }
3441 #endif // AM_HAL_DISABLE_API_VALIDATION
3442             //
3443             // Check to see if there is enough room in the CQ
3444             //
3445             if ((pIOMState->ui32NumPendTransactions == AM_HAL_IOM_MAX_PENDING_TRANSACTIONS) ||
3446                 (am_hal_cmdq_alloc_block(pIOMState->pCmdQHdl, pCqRaw->numEntries + 3, &pCQBlock, &index)))
3447             {
3448                 return AM_HAL_STATUS_OUT_OF_RANGE;
3449             }
3450 
3451             pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQPAUSEEN;
3452             pCQBlock->value = get_pause_val(pIOMState, pCqRaw->ui32PauseCondition);
3453             pCQBlock++;
3454             for (uint32_t i = 0; i < pCqRaw->numEntries; i++, pCQBlock++)
3455             {
3456                 pCQBlock->address = pCqRaw->pCQEntry[i].address;
3457                 pCQBlock->value = pCqRaw->pCQEntry[i].value;
3458             }
3459             // If there is a need - populate the jump back address
3460             if (pCqRaw->pJmpAddr)
3461             {
3462                 *(pCqRaw->pJmpAddr) = (uint32_t)pCQBlock;
3463             }
3464             pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQPAUSEEN;
3465             pCQBlock->value = AM_HAL_IOM_PAUSE_DEFAULT;
3466             pCQBlock++;
3467             pCQBlock->address = (uint32_t)&IOMn(pIOMState->ui32Module)->CQSETCLEAR;
3468             pCQBlock->value = pCqRaw->ui32StatusSetClr;
3469 
3470             pfnCallback1 = pCqRaw->pfnCallback;
3471             if (!pfnCallback1 && !pIOMState->block && (pIOMState->eSeq == AM_HAL_IOM_SEQ_NONE) &&
3472                 (pIOMState->ui32NumUnSolicited >= (pIOMState->ui32MaxPending / 2)))
3473             {
3474                 // Need to schedule a dummy callback, to ensure ui32NumPendTransactions get updated in ISR
3475                 pfnCallback1 = iom_dummy_callback;
3476             }
3477             //
3478             // Store the callback function pointer.
3479             //
3480             pIOMState->pfnCallback[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pfnCallback1;
3481             pIOMState->pCallbackCtxt[index & (AM_HAL_IOM_MAX_PENDING_TRANSACTIONS - 1)] = pCqRaw->pCallbackCtxt;
3482 
3483             //
3484             // Need to protect access of ui32NumPendTransactions as it is accessed
3485             // from ISR as well
3486             //
3487             // Start a critical section.
3488             //
3489             ui32Critical = am_hal_interrupt_master_disable();
3490 
3491             //
3492             // Register for interrupt only if there is a callback
3493             //
3494             status = am_hal_cmdq_post_block(pIOMState->pCmdQHdl, pfnCallback1);
3495 
3496             if (status == AM_HAL_STATUS_SUCCESS)
3497             {
3498                 uint32_t ui32NumPend = pIOMState->ui32NumPendTransactions++;
3499                 pIOMState->ui32NumSeqTransactions++;
3500                 if (pCqRaw->pfnCallback)
3501                 {
3502                     pIOMState->bAutonomous = false;
3503                     pIOMState->ui32NumUnSolicited = 0;
3504                 }
3505                 else
3506                 {
3507                     if (pfnCallback1)
3508                     {
3509                         // This implies we have already scheduled a dummy callback
3510                         pIOMState->ui32NumUnSolicited = 0;
3511                     }
3512                     else
3513                     {
3514                         pIOMState->ui32NumUnSolicited++;
3515                     }
3516                 }
3517                 if (0 == ui32NumPend)
3518                 {
3519                     pIOMState->ui32UserIntCfg = IOMn(ui32Module)->INTEN;
3520                     IOM_SET_INTEN(ui32Module, AM_HAL_IOM_INT_CQMODE);
3521                     // Re-enable the CQ
3522                     am_hal_iom_CQEnable(pIOMState);
3523                 }
3524             }
3525             else
3526             {
3527                 am_hal_cmdq_release_block(pIOMState->pCmdQHdl);
3528             }
3529             //
3530             // End the critical section.
3531             //
3532             am_hal_interrupt_master_set(ui32Critical);
3533             break;
3534         }
3535 
3536 
3537         default:
3538             status = AM_HAL_STATUS_INVALID_ARG;
3539     }
3540 
3541     return status;
3542 }
3543 
3544 //
3545 // IOM High Priority transfer function
3546 //
am_hal_iom_highprio_transfer(void * pHandle,am_hal_iom_transfer_t * psTransaction,am_hal_iom_callback_t pfnCallback,void * pCallbackCtxt)3547 uint32_t am_hal_iom_highprio_transfer(void *pHandle,
3548                                       am_hal_iom_transfer_t *psTransaction,
3549                                       am_hal_iom_callback_t pfnCallback,
3550                                       void *pCallbackCtxt)
3551 {
3552     am_hal_iom_state_t           *pIOMState = (am_hal_iom_state_t *)pHandle;
3553     uint32_t                      ui32Status = AM_HAL_STATUS_SUCCESS;
3554 
3555 #ifndef AM_HAL_DISABLE_API_VALIDATION
3556     uint32_t    ui32SRAMAddress;
3557 
3558     //
3559     // Check the handle.
3560     //
3561     if (!AM_HAL_IOM_CHK_HANDLE(pHandle))
3562     {
3563         return AM_HAL_STATUS_INVALID_HANDLE;
3564     }
3565     if (!pIOMState->pNBTxnBuf)
3566     {
3567         return AM_HAL_STATUS_INVALID_OPERATION;
3568     }
3569     //
3570     // Validate parameters
3571     //
3572     ui32Status = validate_transaction(pIOMState, psTransaction, false);
3573 
3574     if (ui32Status != AM_HAL_STATUS_SUCCESS)
3575     {
3576         return ui32Status;
3577     }
3578     if (psTransaction->ui32PauseCondition != 0)
3579     {
3580         return AM_HAL_STATUS_INVALID_ARG;
3581     }
3582     if (psTransaction->ui32StatusSetClr != 0)
3583     {
3584         return AM_HAL_STATUS_INVALID_ARG;
3585     }
3586     if (psTransaction->eDirection > AM_HAL_IOM_RX)
3587     {
3588         return AM_HAL_STATUS_INVALID_OPERATION;
3589     }
3590     if (!pIOMState->pHPTransactions)
3591     {
3592         return AM_HAL_STATUS_INVALID_OPERATION;
3593     }
3594     //
3595     // Check for DMA to/from DTCM.
3596     //
3597     ui32SRAMAddress = (psTransaction->eDirection == AM_HAL_IOM_TX) ? (uint32_t)psTransaction->pui32TxBuffer : (uint32_t)psTransaction->pui32RxBuffer;
3598 
3599     if ( (ui32SRAMAddress >= AM_HAL_FLASH_DTCM_START) &&
3600       (ui32SRAMAddress <= AM_HAL_FLASH_DTCM_END) )
3601     {
3602       return AM_HAL_STATUS_OUT_OF_RANGE;
3603     }
3604 #endif // AM_HAL_DISABLE_API_VALIDATION
3605 
3606 
3607     ui32Status = iom_add_hp_transaction(pHandle, psTransaction, pfnCallback, pCallbackCtxt);
3608 
3609     if (ui32Status == AM_HAL_STATUS_SUCCESS)
3610     {
3611         if (!(pIOMState->block))
3612         {
3613             ui32Status = sched_hiprio(pIOMState, 1);
3614         }
3615         else
3616         {
3617             pIOMState->ui32NumHPPendingEntries++;
3618         }
3619     }
3620 
3621     //
3622     // Return the status.
3623     //
3624     return ui32Status;
3625 }
3626 
3627 //*****************************************************************************
3628 //
3629 // End Doxygen group.
3630 //! @}
3631 //
3632 //*****************************************************************************
3633