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