1 //*****************************************************************************
2 //
3 //! @file am_hal_ios.c
4 //!
5 //! @brief Functions for Interfacing with the IO Slave module
6 //!
7 //! @addtogroup ios3p IOS - IO Slave (SPI/I2C)
8 //! @ingroup apollo3p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, 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_1_1-10cda4b5e0 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 #define AM_HAL_IOS_MAX_SW_FIFO_SIZE 1023
53 #define AM_HAL_MAGIC_IOS            0x123456
54 #define AM_HAL_IOS_CHK_HANDLE(h)    ((h) && ((am_hal_handle_prefix_t *)(h))->s.bInit && (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_IOS))
55 
56 //*****************************************************************************
57 //
58 //! SRAM Buffer structure
59 //
60 //*****************************************************************************
61 am_hal_ios_buffer_t g_sSRAMBuffer;
62 
63 //*****************************************************************************
64 //
65 //! Private Types.
66 //
67 //*****************************************************************************
68 typedef struct
69 {
70     bool        bValid;
71     uint32_t    regFIFOCFG;
72     uint32_t    regFIFOTHR;
73     uint32_t    regCFG;
74     uint32_t    regINTEN;
75     uint32_t    regACCINTEN;
76 } am_hal_ios_register_state_t;
77 
78 typedef struct
79 {
80     am_hal_handle_prefix_t  prefix;
81     //
82     //! Physical module number.
83     //
84     uint32_t                ui32Module;
85 
86     am_hal_ios_register_state_t registerState;
87 
88     uint8_t *pui8FIFOBase;
89     uint8_t *pui8FIFOEnd;
90     uint8_t *pui8FIFOPtr;
91     uint8_t ui32HwFifoSize;
92     uint32_t ui32FifoBaseOffset;
93 } am_hal_ios_state_t;
94 
95 //*****************************************************************************
96 //
97 // Forward declarations of static funcitons.
98 //
99 //*****************************************************************************
100 static void am_hal_ios_buffer_init(am_hal_ios_buffer_t *psBuffer,
101                                    void *pvArray, uint32_t ui32Bytes);
102 static void fifo_write(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes);
103 static uint32_t am_hal_ios_fifo_ptr_set(void *pHandle, uint32_t ui32Offset);
104 //*****************************************************************************
105 //
106 // Function-like macros.
107 //
108 //*****************************************************************************
109 #define am_hal_ios_buffer_empty(psBuffer)                                   \
110     ((psBuffer)->ui32Length == 0)
111 
112 #define am_hal_ios_buffer_full(psBuffer)                                    \
113     ((psBuffer)->ui32Length == (psBuffer)->ui32Capacity)
114 
115 #define am_hal_ios_buffer_data_left(psBuffer)                               \
116     ((psBuffer)->ui32Length)
117 
118 //*****************************************************************************
119 //
120 // Global Variables
121 //
122 //*****************************************************************************
123 volatile uint8_t * const am_hal_ios_pui8LRAM = (uint8_t *)REG_IOSLAVE_BASEADDR;
124 
125 am_hal_ios_state_t g_IOShandles[AM_REG_IOSLAVE_NUM_MODULES];
126 
127 //*****************************************************************************
128 //
129 // IOS power control function
130 //
131 //*****************************************************************************
am_hal_ios_power_ctrl(void * pHandle,am_hal_sysctrl_power_state_e ePowerState,bool bRetainState)132 uint32_t am_hal_ios_power_ctrl(void *pHandle,
133                                am_hal_sysctrl_power_state_e ePowerState,
134                                bool bRetainState)
135 {
136     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
137 
138 #ifndef AM_HAL_DISABLE_API_VALIDATION
139     if ( !AM_HAL_IOS_CHK_HANDLE(pHandle) )
140     {
141         return AM_HAL_STATUS_INVALID_HANDLE;
142     }
143 #endif // AM_HAL_DISABLE_API_VALIDATION
144 
145     //
146     // Decode the requested power state and update IOS operation accordingly.
147     //
148     switch (ePowerState)
149     {
150         case AM_HAL_SYSCTRL_WAKE:
151             if (bRetainState && !pIOSState->registerState.bValid)
152             {
153                 return AM_HAL_STATUS_INVALID_OPERATION;
154             }
155 
156             //
157             // Enable power control.
158             //
159             am_hal_pwrctrl_periph_enable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_IOS + pIOSState->ui32Module));
160 
161             if (bRetainState)
162             {
163                 //
164                 // Restore IOS registers
165                 IOSLAVEn(pIOSState->ui32Module)->FIFOCFG     = pIOSState->registerState.regFIFOCFG;
166                 IOSLAVEn(pIOSState->ui32Module)->FIFOTHR     = pIOSState->registerState.regFIFOTHR;
167                 IOSLAVEn(pIOSState->ui32Module)->CFG         = pIOSState->registerState.regCFG;
168                 IOSLAVEn(pIOSState->ui32Module)->INTEN       = pIOSState->registerState.regINTEN;
169                 IOSLAVEn(pIOSState->ui32Module)->REGACCINTEN = pIOSState->registerState.regACCINTEN;
170 
171                 pIOSState->registerState.bValid = false;
172             }
173             break;
174 
175         case AM_HAL_SYSCTRL_NORMALSLEEP:
176         case AM_HAL_SYSCTRL_DEEPSLEEP:
177             if (bRetainState)
178             {
179                 // Save IOS Registers
180                 pIOSState->registerState.regFIFOCFG    = IOSLAVEn(pIOSState->ui32Module)->FIFOCFG;
181                 pIOSState->registerState.regFIFOTHR    = IOSLAVEn(pIOSState->ui32Module)->FIFOTHR;
182                 pIOSState->registerState.regCFG        = IOSLAVEn(pIOSState->ui32Module)->CFG;
183                 pIOSState->registerState.regINTEN      = IOSLAVEn(pIOSState->ui32Module)->INTEN;
184                 pIOSState->registerState.regACCINTEN   = IOSLAVEn(pIOSState->ui32Module)->REGACCINTEN;
185                 pIOSState->registerState.bValid = true;
186             }
187 
188             //
189             // Disable power control.
190             //
191             am_hal_pwrctrl_periph_disable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_IOS + pIOSState->ui32Module));
192             break;
193 
194         default:
195             return AM_HAL_STATUS_INVALID_ARG;
196     }
197 
198     //
199     // Return the status.
200     //
201     return AM_HAL_STATUS_SUCCESS;
202 } // am_hal_ios_power_ctrl()
203 
204 //*****************************************************************************
205 //
206 // IOS uninitialize function
207 //
208 //*****************************************************************************
am_hal_ios_uninitialize(void * pHandle)209 uint32_t am_hal_ios_uninitialize(void *pHandle)
210 {
211     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
212 
213 #ifndef AM_HAL_DISABLE_API_VALIDATION
214     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
215     {
216         return AM_HAL_STATUS_INVALID_HANDLE;
217     }
218 #endif // AM_HAL_DISABLE_API_VALIDATION
219 
220     if (pIOSState->prefix.s.bEnable)
221     {
222         am_hal_ios_disable(pHandle);
223     }
224 
225     pIOSState->prefix.s.bInit = false;
226 
227     return AM_HAL_STATUS_SUCCESS;
228 } // am_hal_ios_uninitialize()
229 
230 
231 //*****************************************************************************
232 //
233 // IOS initialization function
234 //
235 //*****************************************************************************
am_hal_ios_initialize(uint32_t ui32Module,void ** ppHandle)236 uint32_t am_hal_ios_initialize(uint32_t ui32Module, void **ppHandle)
237 {
238 #ifndef AM_HAL_DISABLE_API_VALIDATION
239     //
240     // Validate the module number
241     //
242     if ( ui32Module >= AM_REG_IOSLAVE_NUM_MODULES )
243     {
244         return AM_HAL_STATUS_OUT_OF_RANGE;
245     }
246 
247     if (ppHandle == NULL)
248     {
249         return AM_HAL_STATUS_INVALID_ARG;
250     }
251 
252     if (g_IOShandles[ui32Module].prefix.s.bInit)
253     {
254         return AM_HAL_STATUS_INVALID_OPERATION;
255     }
256 #endif // AM_HAL_DISABLE_API_VALIDATION
257 
258     g_IOShandles[ui32Module].prefix.s.bInit = true;
259     g_IOShandles[ui32Module].prefix.s.bEnable = false;
260     g_IOShandles[ui32Module].prefix.s.magic = AM_HAL_MAGIC_IOS;
261 
262     //
263     // Initialize the handle.
264     //
265     g_IOShandles[ui32Module].ui32Module = ui32Module;
266 
267     //
268     // Return the handle.
269     //
270     *ppHandle = (void *)&g_IOShandles[ui32Module];
271 
272     return AM_HAL_STATUS_SUCCESS;
273 } // am_hal_ios_initialize()
274 
275 //*****************************************************************************
276 //
277 // IOS enable function
278 //
279 //*****************************************************************************
am_hal_ios_enable(void * pHandle)280 uint32_t am_hal_ios_enable(void *pHandle)
281 {
282     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
283 #ifndef AM_HAL_DISABLE_API_VALIDATION
284     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
285     {
286         return AM_HAL_STATUS_INVALID_HANDLE;
287     }
288 
289     if (pIOSState->prefix.s.bEnable)
290     {
291         return AM_HAL_STATUS_SUCCESS;
292     }
293 #endif // AM_HAL_DISABLE_API_VALIDATION
294 
295     IOSLAVEn(pIOSState->ui32Module)->CFG |= _VAL2FLD(IOSLAVE_CFG_IFCEN, 1);
296 
297     pIOSState->prefix.s.bEnable = true;
298 
299     return AM_HAL_STATUS_SUCCESS;
300 } // am_hal_ios_enable()
301 
302 //*****************************************************************************
303 //
304 // IOS disable function
305 //
306 //*****************************************************************************
am_hal_ios_disable(void * pHandle)307 uint32_t am_hal_ios_disable(void *pHandle)
308 {
309     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
310 
311 #ifndef AM_HAL_DISABLE_API_VALIDATION
312     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
313     {
314         return AM_HAL_STATUS_INVALID_HANDLE;
315     }
316 #endif // AM_HAL_DISABLE_API_VALIDATION
317 
318     if (!pIOSState->prefix.s.bEnable)
319     {
320         return AM_HAL_STATUS_SUCCESS;
321     }
322 
323     IOSLAVEn(pIOSState->ui32Module)->CFG &= ~(_VAL2FLD(IOSLAVE_CFG_IFCEN, 1));
324 
325     pIOSState->prefix.s.bEnable = false;
326 
327     return AM_HAL_STATUS_SUCCESS;
328 
329 } // am_hal_ios_disable()
330 
331 //*****************************************************************************
332 //
333 // IOS configuration function.
334 //
335 //*****************************************************************************
am_hal_ios_configure(void * pHandle,am_hal_ios_config_t * psConfig)336 uint32_t am_hal_ios_configure(void *pHandle, am_hal_ios_config_t *psConfig)
337 {
338     uint32_t ui32LRAMConfig = 0;
339     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
340     uint32_t ui32Module;
341 
342 #ifndef AM_HAL_DISABLE_API_VALIDATION
343     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
344     {
345         return AM_HAL_STATUS_INVALID_HANDLE;
346     }
347 
348     //
349     // Validate the parameters
350     //
351     if ( (psConfig == NULL) ||
352          (pIOSState->ui32Module >= AM_REG_IOSLAVE_NUM_MODULES) )
353     {
354         return AM_HAL_STATUS_INVALID_ARG;
355     }
356     // Configure not allowed in Enabled state
357     if (pIOSState->prefix.s.bEnable)
358     {
359         return AM_HAL_STATUS_INVALID_OPERATION;
360     }
361 #endif // AM_HAL_DISABLE_API_VALIDATION
362 
363     ui32Module = pIOSState->ui32Module;
364 
365     //
366     // Record the FIFO parameters for later use.
367     //
368     pIOSState->pui8FIFOBase = (uint8_t *)(REG_IOSLAVE_BASEADDR + psConfig->ui32FIFOBase);
369     pIOSState->pui8FIFOEnd = (uint8_t *)(REG_IOSLAVE_BASEADDR + psConfig->ui32RAMBase);
370     pIOSState->ui32HwFifoSize = pIOSState->pui8FIFOEnd - pIOSState->pui8FIFOBase;
371     pIOSState->ui32FifoBaseOffset = psConfig->ui32FIFOBase;
372 
373     //
374     // Initialize the global SRAM buffer
375     // Total size, which is SRAM Buffer plus the hardware FIFO needs to be
376     // limited to 1023
377     //
378     if ( psConfig->ui32SRAMBufferCap > (AM_HAL_IOS_MAX_SW_FIFO_SIZE - pIOSState->ui32HwFifoSize + 1) )
379     {
380         psConfig->ui32SRAMBufferCap = (AM_HAL_IOS_MAX_SW_FIFO_SIZE - pIOSState->ui32HwFifoSize + 1);
381     }
382     am_hal_ios_buffer_init(&g_sSRAMBuffer, psConfig->pui8SRAMBuffer, psConfig->ui32SRAMBufferCap);
383 
384     //
385     // Calculate the value for the IO Slave FIFO configuration register.
386     //
387     ui32LRAMConfig  = _VAL2FLD(IOSLAVE_FIFOCFG_ROBASE,   psConfig->ui32ROBase >> 3);
388     ui32LRAMConfig |= _VAL2FLD(IOSLAVE_FIFOCFG_FIFOBASE, psConfig->ui32FIFOBase >> 3);
389     ui32LRAMConfig |= _VAL2FLD(IOSLAVE_FIFOCFG_FIFOMAX,  psConfig->ui32RAMBase >> 3);
390 
391     //
392     // Just in case, disable the IOS
393     //
394     am_hal_ios_disable(pHandle);
395 
396     //
397     // Write the configuration register with the user's selected interface
398     // characteristics.
399     //
400     IOSLAVEn(ui32Module)->CFG = psConfig->ui32InterfaceSelect;
401 
402     //
403     // Write the FIFO configuration register to set the memory map for the LRAM.
404     //
405     IOSLAVEn(ui32Module)->FIFOCFG = ui32LRAMConfig;
406 
407     //
408     // Clear the FIFO State
409     //
410     IOSLAVEn(pIOSState->ui32Module)->FIFOCTR_b.FIFOCTR = 0x0;
411     IOSLAVEn(pIOSState->ui32Module)->FIFOPTR_b.FIFOSIZ = 0x0;
412     am_hal_ios_fifo_ptr_set(pHandle, pIOSState->ui32FifoBaseOffset);
413 
414     //
415     // Enable the IOS. The following configuration options can't be set while
416     // the IOS is disabled.
417     //
418     am_hal_ios_enable(pHandle);
419 
420     //
421     // Initialize the FIFO pointer to the beginning of the FIFO section.
422     //
423     am_hal_ios_fifo_ptr_set(pHandle, psConfig->ui32FIFOBase);
424 
425     //
426     // Write the FIFO threshold register.
427     //
428     IOSLAVEn(ui32Module)->FIFOTHR = psConfig->ui32FIFOThreshold;
429 
430     return AM_HAL_STATUS_SUCCESS;
431 } // am_hal_ios_config()
432 
433 //*****************************************************************************
434 //
435 // IOS enable interrupts function
436 //
437 //*****************************************************************************
am_hal_ios_interrupt_enable(void * pHandle,uint32_t ui32IntMask)438 uint32_t am_hal_ios_interrupt_enable(void *pHandle, uint32_t ui32IntMask)
439 {
440     uint32_t ui32Module;
441 
442 #ifndef AM_HAL_DISABLE_API_VALIDATION
443     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
444     {
445         return AM_HAL_STATUS_INVALID_HANDLE;
446     }
447 #endif // AM_HAL_DISABLE_API_VALIDATION
448 
449     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
450 
451     //
452     // OR the desired interrupt into the enable register.
453     //
454     IOSLAVEn(ui32Module)->INTEN |= ui32IntMask;
455 
456     return AM_HAL_STATUS_SUCCESS;
457 } // am_hal_ios_int_enable()
458 
459 //*****************************************************************************
460 //
461 // IOS disable interrupts function
462 //
463 //*****************************************************************************
am_hal_ios_interrupt_disable(void * pHandle,uint32_t ui32IntMask)464 uint32_t am_hal_ios_interrupt_disable(void *pHandle, uint32_t ui32IntMask)
465 {
466     uint32_t ui32Module;
467 
468 #ifndef AM_HAL_DISABLE_API_VALIDATION
469     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
470     {
471         return AM_HAL_STATUS_INVALID_HANDLE;
472     }
473 #endif // AM_HAL_DISABLE_API_VALIDATION
474 
475     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
476 
477     //
478     // Clear the desired bit from the interrupt enable register.
479     //
480     IOSLAVEn(ui32Module)->INTEN &= ~(ui32IntMask);
481 
482     return AM_HAL_STATUS_SUCCESS;
483 } // am_hal_ios_int_disable()
484 
485 //*****************************************************************************
486 //
487 // IOS interrupt clear
488 //
489 //*****************************************************************************
am_hal_ios_interrupt_clear(void * pHandle,uint32_t ui32IntMask)490 uint32_t am_hal_ios_interrupt_clear(void *pHandle, uint32_t ui32IntMask)
491 {
492     uint32_t ui32Module;
493 
494 #ifndef AM_HAL_DISABLE_API_VALIDATION
495     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
496     {
497         return AM_HAL_STATUS_INVALID_HANDLE;
498     }
499 #endif // AM_HAL_DISABLE_API_VALIDATION
500 
501     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
502 
503     //
504     // Use the interrupt clear register to deactivate the chosen interrupt.
505     //
506     IOSLAVEn(ui32Module)->INTCLR = ui32IntMask;
507 
508     return AM_HAL_STATUS_SUCCESS;
509 } // am_hal_ios_int_clear()
510 
511 //*****************************************************************************
512 //
513 // IOS get interrupt status
514 //
515 //*****************************************************************************
am_hal_ios_interrupt_status_get(void * pHandle,bool bEnabledOnly,uint32_t * pui32IntStatus)516 uint32_t am_hal_ios_interrupt_status_get(void *pHandle, bool bEnabledOnly,
517                                          uint32_t *pui32IntStatus)
518 {
519     uint32_t ui32IntStatus = 0;
520     uint32_t ui32Module;
521 
522 #ifndef AM_HAL_DISABLE_API_VALIDATION
523     if ( !AM_HAL_IOS_CHK_HANDLE(pHandle) )
524     {
525         return AM_HAL_STATUS_INVALID_HANDLE;
526     }
527 
528     if ( !pui32IntStatus )
529     {
530         return AM_HAL_STATUS_INVALID_ARG;
531     }
532 #endif // AM_HAL_DISABLE_API_VALIDATION
533 
534     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
535 
536     ui32IntStatus = IOSLAVEn(ui32Module)->INTSTAT;
537 
538     if ( bEnabledOnly )
539     {
540         ui32IntStatus &= IOSLAVEn(ui32Module)->INTEN;
541     }
542 
543     *pui32IntStatus = ui32IntStatus;
544 
545     return AM_HAL_STATUS_SUCCESS;
546 } // am_hal_ios_int_status_get()
547 
548 //*****************************************************************************
549 //
550 // @brief Check the amount of space used in the FIFO
551 //
552 // @param pHandle        - IOS handle
553 // @param pui32UsedSpace is bytes used in the Overall FIFO.
554 //
555 // This function returns the available data in the overall FIFO yet to be
556 // read by the host. This takes into account the SRAM buffer and hardware FIFO
557 //
558 // @return success or error code
559 //
560 //*****************************************************************************
am_hal_ios_fifo_space_used(void * pHandle,uint32_t * pui32UsedSpace)561 uint32_t am_hal_ios_fifo_space_used(void *pHandle, uint32_t *pui32UsedSpace)
562 {
563     uint32_t ui32Module;
564     uint32_t ui32Val = 0;
565 
566 #ifndef AM_HAL_DISABLE_API_VALIDATION
567     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
568     {
569         return AM_HAL_STATUS_INVALID_HANDLE;
570     }
571     if ( !pui32UsedSpace )
572     {
573         return AM_HAL_STATUS_INVALID_ARG;
574     }
575 #endif // AM_HAL_DISABLE_API_VALIDATION
576 
577     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
578 
579     //
580     // Start a critical section for thread safety.
581     //
582     AM_CRITICAL_BEGIN
583 
584     ui32Val = g_sSRAMBuffer.ui32Length;
585     ui32Val += IOSLAVEn(ui32Module)->FIFOPTR_b.FIFOSIZ;
586 
587     //
588     // End the critical section
589     //
590     AM_CRITICAL_END
591 
592     *pui32UsedSpace = ui32Val;
593 
594     return AM_HAL_STATUS_SUCCESS;
595 } // am_hal_ios_fifo_space_used()
596 
597 //*****************************************************************************
598 //
599 // @brief Check the amount of space left in the FIFO
600 //
601 // @param pHandle        - IOS handle
602 // @param pui32LeftSpace is bytes left in the Overall FIFO.
603 //
604 // This function returns the available space in the overall FIFO to accept
605 // new data. This takes into account the SRAM buffer and hardware FIFO
606 //
607 // @return success or error code
608 //
609 //*****************************************************************************
am_hal_ios_fifo_space_left(void * pHandle,uint32_t * pui32LeftSpace)610 uint32_t am_hal_ios_fifo_space_left(void *pHandle, uint32_t *pui32LeftSpace)
611 {
612     uint32_t ui32Module;
613     uint32_t ui32Val = 0;
614 
615 #ifndef AM_HAL_DISABLE_API_VALIDATION
616     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
617     {
618         return AM_HAL_STATUS_INVALID_HANDLE;
619     }
620     if ( !pui32LeftSpace )
621     {
622         return AM_HAL_STATUS_INVALID_ARG;
623     }
624 #endif // AM_HAL_DISABLE_API_VALIDATION
625 
626     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
627 
628     //
629     // Start a critical section for thread safety.
630     //
631     AM_CRITICAL_BEGIN
632 
633     //
634     // We waste one byte in HW FIFO
635     //
636     ui32Val = g_sSRAMBuffer.ui32Capacity + ((am_hal_ios_state_t*)pHandle)->ui32HwFifoSize - 1;
637     ui32Val -= g_sSRAMBuffer.ui32Length;
638     ui32Val -= IOSLAVEn(ui32Module)->FIFOPTR_b.FIFOSIZ;
639 
640     //
641     // End the critical section
642     //
643     AM_CRITICAL_END
644 
645     *pui32LeftSpace = ui32Val;
646 
647     return AM_HAL_STATUS_SUCCESS;
648 } // am_hal_ios_fifo_space_left()
649 
650 //*****************************************************************************
651 //
652 // @brief Check the amount of space left in the hardware FIFO
653 //
654 // @param pHandle        - IOS handle
655 // @param pui32LeftSpace is bytes left in the IOS FIFO.
656 //
657 // This function reads the IOSLAVE FIFOPTR register and determines the amount
658 // of space left in the IOS LRAM FIFO.
659 //
660 // @return success or error code
661 //
662 //*****************************************************************************
fifo_space_left(void * pHandle,uint32_t * pui32LeftSpace)663 static uint32_t fifo_space_left(void *pHandle, uint32_t *pui32LeftSpace)
664 {
665     uint32_t ui32Module;
666 
667 #ifndef AM_HAL_DISABLE_API_VALIDATION
668     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
669     {
670         return AM_HAL_STATUS_INVALID_HANDLE;
671     }
672     if ( !pui32LeftSpace )
673     {
674         return AM_HAL_STATUS_INVALID_ARG;
675     }
676 #endif // AM_HAL_DISABLE_API_VALIDATION
677 
678     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
679 
680     //
681     // We waste one byte in HW FIFO
682     //
683     *pui32LeftSpace = ((uint32_t)((am_hal_ios_state_t*)pHandle)->ui32HwFifoSize - IOSLAVEn(ui32Module)->FIFOPTR_b.FIFOSIZ - 1);
684 
685     return AM_HAL_STATUS_SUCCESS;
686 } // fifo_space_left()
687 
688 //*****************************************************************************
689 // @brief Helper function for managing IOS FIFO writes.
690 //
691 // @param pHandle
692 // @param pui8Data
693 // @param ui32NumBytes
694 //*****************************************************************************
fifo_write(void * pHandle,uint8_t * pui8Data,uint32_t ui32NumBytes)695 static void fifo_write(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes)
696 {
697     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
698     uint8_t *pFifoPtr = pIOSState->pui8FIFOPtr;
699     uint8_t *pFifoBase = pIOSState->pui8FIFOBase;
700     uint8_t *pFifoEnd = pIOSState->pui8FIFOEnd;
701 
702     while ( ui32NumBytes )
703     {
704         //
705         // Write the data to the FIFO
706         //
707         *pFifoPtr++ = *pui8Data++;
708         ui32NumBytes--;
709 
710         //
711         // Make sure to wrap the FIFO pointer if necessary.
712         //
713         if ( pFifoPtr == pFifoEnd )
714         {
715             pFifoPtr = pFifoBase;
716         }
717     }
718     pIOSState->pui8FIFOPtr = pFifoPtr;
719 } // fifo_write()
720 
721 //*****************************************************************************
722 //
723 // IOS interrupt service routine
724 //
725 //*****************************************************************************
am_hal_ios_interrupt_service(void * pHandle,uint32_t ui32IntMask)726 uint32_t am_hal_ios_interrupt_service(void *pHandle, uint32_t ui32IntMask)
727 {
728     uint32_t thresh;
729     uint32_t freeSpace, usedSpace, chunk1, chunk2, ui32WriteIndex;
730     uint32_t ui32Module;
731 
732 #ifndef AM_HAL_DISABLE_API_VALIDATION
733     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
734     {
735         return AM_HAL_STATUS_INVALID_HANDLE;
736     }
737 #endif // AM_HAL_DISABLE_API_VALIDATION
738 
739     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
740 
741     //
742     // Check for FIFO size interrupts.
743     //
744     if ( ui32IntMask & AM_HAL_IOS_INT_FSIZE )
745     {
746         thresh = IOSLAVEn(ui32Module)->FIFOTHR_b.FIFOTHR;
747 
748         //
749         // While the FIFO is at or below threshold Add more data
750         // If Fifo level is above threshold, we're guaranteed an FSIZ interrupt
751         //
752         while ( g_sSRAMBuffer.ui32Length &&
753                 ((usedSpace = IOSLAVEn(ui32Module)->FIFOPTR_b.FIFOSIZ) <= thresh) )
754         {
755             //
756             // So, we do have some data in SRAM which needs to be moved to FIFO.
757             // A chunk of data is a continguous set of bytes in SRAM that can be
758             //  written to FIFO. Determine the chunks of data from SRAM that can
759             //  be written. Up to two chunks possible
760             //
761             ui32WriteIndex = g_sSRAMBuffer.ui32WriteIndex;
762             chunk1 = ((ui32WriteIndex > (uint32_t)g_sSRAMBuffer.ui32ReadIndex) ?   \
763                         (ui32WriteIndex - (uint32_t)g_sSRAMBuffer.ui32ReadIndex) : \
764                         (g_sSRAMBuffer.ui32Capacity - (uint32_t)g_sSRAMBuffer.ui32ReadIndex));
765             chunk2 = g_sSRAMBuffer.ui32Length - chunk1;
766             // We waste one byte in HW FIFO
767             freeSpace = ((am_hal_ios_state_t*)pHandle)->ui32HwFifoSize - usedSpace - 1;
768             // Write data in chunks
769             // Determine the chunks of data from SRAM that can be written
770             if ( chunk1 > freeSpace )
771             {
772                 fifo_write(pHandle, (uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), freeSpace);
773                 //
774                 // Advance the read index, wrapping if needed.
775                 //
776                 g_sSRAMBuffer.ui32ReadIndex += freeSpace;
777                 // No need to check for wrap as we wrote less than chunk1
778                 //
779                 // Adjust the length value to reflect the change.
780                 //
781                 g_sSRAMBuffer.ui32Length -= freeSpace;
782             }
783             else
784             {
785                 fifo_write(pHandle, (uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), chunk1);
786 
787                 //
788                 // Update the read index - wrapping as needed
789                 //
790                 g_sSRAMBuffer.ui32ReadIndex += chunk1;
791                 g_sSRAMBuffer.ui32ReadIndex %= g_sSRAMBuffer.ui32Capacity;
792                 //
793                 // Adjust the length value to reflect the change.
794                 //
795                 g_sSRAMBuffer.ui32Length -= chunk1;
796                 freeSpace -= chunk1;
797 
798                 if ( freeSpace && chunk2 )
799                 {
800                     if ( chunk2 > freeSpace )
801                     {
802                         fifo_write(pHandle, (uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), freeSpace);
803 
804                         //
805                         // Advance the read index, wrapping if needed.
806                         //
807                         g_sSRAMBuffer.ui32ReadIndex += freeSpace;
808 
809                         // No need to check for wrap in chunk2
810                         //
811                         // Adjust the length value to reflect the change.
812                         //
813                         g_sSRAMBuffer.ui32Length -= freeSpace;
814                     }
815                     else
816                     {
817                         fifo_write(pHandle, (uint8_t *)(g_sSRAMBuffer.pui8Data + g_sSRAMBuffer.ui32ReadIndex), chunk2);
818                         //
819                         // Advance the read index, wrapping if needed.
820                         //
821                         g_sSRAMBuffer.ui32ReadIndex += chunk2;
822 
823                         // No need to check for wrap in chunk2
824                         //
825                         // Adjust the length value to reflect the change.
826                         //
827                         g_sSRAMBuffer.ui32Length -= chunk2;
828                     }
829                 }
830             }
831 
832             //
833             // Need to retake the FIFO space, after Threshold interrupt has been reenabled
834             // Clear any spurious FSIZE interrupt that might have got raised
835             //
836             IOSLAVEn(ui32Module)->INTCLR_b.FSIZE = 1;
837         }
838     }
839 
840     return AM_HAL_STATUS_SUCCESS;
841 } // am_hal_ios_fifo_service()
842 
843 //*****************************************************************************
844 //
845 // @brief Writes the specified number of bytes to the IOS fifo.
846 //
847 // @param pHandle        - IOS handle
848 // @param pui8Data       - pointer to the data to be written to the fifo.
849 // @param ui32NumBytes   - the number of bytes to send.
850 // @param pui32WrittenBytes -number of bytes written (could be less than ui32NumBytes, if not enough space)
851 //
852 // This function will write data from the caller-provided array to the IOS
853 // LRAM FIFO. If there is no space in the LRAM FIFO, the data will be copied
854 // to a temporary SRAM buffer instead.
855 //
856 // The maximum message size for the IO Slave is 1023 bytes.
857 //
858 // @note In order for SRAM copy operations in the function to work correctly,
859 // the \e am_hal_ios_buffer_service() function must be called in the ISR for
860 // the ioslave module.
861 //
862 // @return success or error code
863 //
864 //*****************************************************************************
am_hal_ios_fifo_write(void * pHandle,uint8_t * pui8Data,uint32_t ui32NumBytes,uint32_t * pui32WrittenBytes)865 uint32_t am_hal_ios_fifo_write(void *pHandle, uint8_t *pui8Data, uint32_t ui32NumBytes, uint32_t *pui32WrittenBytes)
866 {
867     uint32_t ui32FIFOSpace = 0;
868     uint32_t ui32SRAMSpace;
869     uint32_t ui32SRAMLength;
870     uint32_t totalBytes = ui32NumBytes;
871     uint32_t ui32Module;
872 
873 #ifndef AM_HAL_DISABLE_API_VALIDATION
874     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
875     {
876         return AM_HAL_STATUS_INVALID_HANDLE;
877     }
878     if ( !pui8Data || !pui32WrittenBytes)
879     {
880         return AM_HAL_STATUS_INVALID_ARG;
881     }
882 #endif // AM_HAL_DISABLE_API_VALIDATION
883 
884     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
885 
886     //
887     // This operation will only work properly if an SRAM buffer has been
888     // allocated. Make sure that am_hal_ios_fifo_buffer_init() has been called,
889     // and the buffer pointer looks valid.
890     //
891     am_hal_debug_assert(g_sSRAMBuffer.pui8Data != 0);
892 
893     if ( ui32NumBytes == 0 )
894     {
895         *pui32WrittenBytes = 0;
896     }
897     else
898     {
899         //
900         // Start a critical section for thread safety.
901         //
902         AM_CRITICAL_BEGIN
903 
904         ui32SRAMLength = g_sSRAMBuffer.ui32Length;
905 
906         //
907         // End the critical section
908         //
909         AM_CRITICAL_END
910 
911         //
912         // If the SRAM buffer is empty, we should just write directly to the FIFO.
913         //
914         if ( ui32SRAMLength == 0 )
915         {
916             fifo_space_left(pHandle, &ui32FIFOSpace);
917 
918             //
919             // If the whole message fits, send it now.
920             //
921             if ( ui32NumBytes <= ui32FIFOSpace )
922             {
923                 fifo_write(pHandle, pui8Data, ui32NumBytes);
924                 ui32NumBytes = 0;
925             }
926             else
927             {
928                 fifo_write(pHandle, pui8Data, ui32FIFOSpace);
929                 ui32NumBytes -= ui32FIFOSpace;
930                 pui8Data += ui32FIFOSpace;
931             }
932         }
933 
934         //
935         // If there's still data, write it to the SRAM buffer.
936         //
937         if ( ui32NumBytes )
938         {
939             uint32_t idx, writeIdx, capacity, fifoSize;
940             ui32SRAMSpace = g_sSRAMBuffer.ui32Capacity - ui32SRAMLength;
941 
942             writeIdx = g_sSRAMBuffer.ui32WriteIndex;
943             capacity = g_sSRAMBuffer.ui32Capacity;
944 
945             //
946             // Make sure that the data will fit inside the SRAM buffer.
947             //
948             if ( ui32SRAMSpace > ui32NumBytes )
949             {
950                 ui32SRAMSpace = ui32NumBytes;
951             }
952 
953             //
954             // If the data will fit, write it to the SRAM buffer.
955             //
956             for ( idx = 0; idx < ui32SRAMSpace; idx++ )
957             {
958                 g_sSRAMBuffer.pui8Data[(idx + writeIdx) % capacity] = pui8Data[idx];
959             }
960 
961             ui32NumBytes -= idx;
962 
963             //
964             // Start a critical section for thread safety before updating length & wrIdx.
965             //
966             AM_CRITICAL_BEGIN
967 
968             //
969             // Advance the write index, making sure to wrap if necessary.
970             //
971             g_sSRAMBuffer.ui32WriteIndex = (idx + writeIdx) % capacity;
972 
973             //
974             // Update the length value appropriately.
975             //
976             g_sSRAMBuffer.ui32Length += idx;
977 
978             //
979             // End the critical section
980             //
981             AM_CRITICAL_END
982 
983             // It is possible that there is a race condition that the FIFO level has
984             // gone below the threshold by the time we set the wrIdx above, and hence
985             // we may never get the threshold interrupt to serve the SRAM data we
986             // just wrote
987 
988             // If that is the case, explicitly generate the FSIZE interrupt from here
989             fifoSize = IOSLAVEn(ui32Module)->FIFOPTR_b.FIFOSIZ;
990 
991             if ( fifoSize <= IOSLAVEn(ui32Module)->FIFOTHR_b.FIFOTHR )
992             {
993                 IOSLAVEn(ui32Module)->INTSET_b.FSIZE = 1;
994             }
995         }
996 
997         *pui32WrittenBytes = totalBytes - ui32NumBytes;
998     }
999 
1000     return AM_HAL_STATUS_SUCCESS;
1001 } // am_hal_ios_fifo_write()
1002 
1003 //*****************************************************************************
1004 //
1005 // @brief Sets the IOS FIFO pointer to the specified LRAM offset.
1006 //
1007 // @param pHandle        - IOS handle
1008 // @param ui32Offset     - LRAM offset to set the FIFO pointer to.
1009 //
1010 // @return success or error code
1011 //
1012 //*****************************************************************************
am_hal_ios_fifo_ptr_set(void * pHandle,uint32_t ui32Offset)1013 static uint32_t am_hal_ios_fifo_ptr_set(void *pHandle, uint32_t ui32Offset)
1014 {
1015     uint32_t ui32Module;
1016 
1017 #ifndef AM_HAL_DISABLE_API_VALIDATION
1018     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
1019     {
1020         return AM_HAL_STATUS_INVALID_HANDLE;
1021     }
1022 #endif // AM_HAL_DISABLE_API_VALIDATION
1023 
1024     ui32Module = ((am_hal_ios_state_t*)pHandle)->ui32Module;
1025 
1026     //
1027     // Start a critical section for thread safety.
1028     //
1029     AM_CRITICAL_BEGIN
1030 
1031     //
1032     // Set the FIFO Update bit.
1033     //
1034     IOSLAVEn(ui32Module)->FUPD = 0x1;
1035 
1036     //
1037     // Change the FIFO offset.
1038     //
1039     IOSLAVEn(ui32Module)->FIFOPTR = ui32Offset;
1040 
1041     //
1042     // Clear the FIFO update bit.
1043     //
1044     IOSLAVEn(ui32Module)->FUPD = 0x0;
1045 
1046     //
1047     // Set the global FIFO-pointer tracking variable.
1048     //
1049     ((am_hal_ios_state_t*)pHandle)->pui8FIFOPtr = (uint8_t *) (REG_IOSLAVE_BASEADDR + ui32Offset);
1050 
1051     //
1052     // End the critical section.
1053     //
1054     AM_CRITICAL_END
1055 
1056     return AM_HAL_STATUS_SUCCESS;
1057 } // am_hal_ios_fifo_ptr_set()
1058 
1059 //*****************************************************************************
1060 //
1061 // @brief Initialize an SRAM buffer for use with the IO Slave.
1062 //
1063 // @param psBuffer
1064 // @param pvArray
1065 // @param ui32Bytes
1066 //
1067 //*****************************************************************************
am_hal_ios_buffer_init(am_hal_ios_buffer_t * psBuffer,void * pvArray,uint32_t ui32Bytes)1068 static void am_hal_ios_buffer_init(am_hal_ios_buffer_t *psBuffer, void *pvArray,
1069                                    uint32_t ui32Bytes)
1070 {
1071     psBuffer->ui32WriteIndex = 0;
1072     psBuffer->ui32ReadIndex = 0;
1073     psBuffer->ui32Length = 0;
1074     psBuffer->ui32Capacity = ui32Bytes;
1075     psBuffer->pui8Data = (uint8_t *)pvArray;
1076 } // am_hal_ios_buffer_init()
1077 
1078 //*****************************************************************************
1079 //
1080 // @brief IOS control function
1081 //
1082 // @param pHandle      - handle for the IOS.
1083 // @param eReq         - device specific special request code.
1084 // @param pArgs        - pointer to the request specific arguments.
1085 //
1086 // This function allows advanced settings
1087 //
1088 // @return success or error code
1089 //
1090 //*****************************************************************************
am_hal_ios_control(void * pHandle,am_hal_ios_request_e eReq,void * pArgs)1091 uint32_t am_hal_ios_control(void *pHandle, am_hal_ios_request_e eReq, void *pArgs)
1092 {
1093     am_hal_ios_state_t *pIOSState = (am_hal_ios_state_t*)pHandle;
1094     uint32_t ui32Val = 0;
1095 
1096 #ifndef AM_HAL_DISABLE_API_VALIDATION
1097     if (!AM_HAL_IOS_CHK_HANDLE(pHandle))
1098     {
1099         return AM_HAL_STATUS_INVALID_HANDLE;
1100     }
1101 
1102     //
1103     // Validate the parameters
1104     //
1105     if ((eReq < AM_HAL_IOS_REQ_ARG_MAX) && (NULL == pArgs))
1106     {
1107         return AM_HAL_STATUS_INVALID_ARG;
1108     }
1109 #endif // AM_HAL_DISABLE_API_VALIDATION
1110 
1111     switch (eReq)
1112     {
1113         case AM_HAL_IOS_REQ_HOST_INTSET:
1114             IOSLAVEn(pIOSState->ui32Module)->IOINTCTL = _VAL2FLD(IOSLAVE_IOINTCTL_IOINTSET, *((uint32_t *)pArgs));
1115             break;
1116         case AM_HAL_IOS_REQ_HOST_INTCLR:
1117             IOSLAVEn(pIOSState->ui32Module)->IOINTCTL = _VAL2FLD(IOSLAVE_IOINTCTL_IOINTCLR, *((uint32_t *)pArgs));
1118             break;
1119         case AM_HAL_IOS_REQ_HOST_INTGET:
1120             *((uint32_t*)pArgs) = IOSLAVEn(pIOSState->ui32Module)->IOINTCTL_b.IOINT;
1121             break;
1122         case AM_HAL_IOS_REQ_HOST_INTEN_GET:
1123             *((uint32_t*)pArgs) = IOSLAVEn(pIOSState->ui32Module)->IOINTCTL_b.IOINTEN;
1124             break;
1125         case AM_HAL_IOS_REQ_READ_GADATA:
1126             *((uint32_t*)pArgs) = IOSLAVEn(pIOSState->ui32Module)->GENADD_b.GADATA;
1127             break;
1128         case AM_HAL_IOS_REQ_READ_POLL:
1129             while ( IOSLAVEn(pIOSState->ui32Module)->FUPD & IOSLAVE_FUPD_IOREAD_Msk );
1130             break;
1131         case AM_HAL_IOS_REQ_FIFO_UPDATE_CTR:
1132             am_hal_ios_fifo_space_used(pHandle, &ui32Val);
1133             IOSLAVEn(pIOSState->ui32Module)->FIFOCTR_b.FIFOCTR = ui32Val;
1134             break;
1135         case AM_HAL_IOS_REQ_FIFO_BUF_CLR:
1136             am_hal_ios_buffer_init(&g_sSRAMBuffer, NULL, 0);
1137             //
1138             // Clear the FIFO State
1139             //
1140             IOSLAVEn(pIOSState->ui32Module)->FIFOCTR_b.FIFOCTR = 0x0;
1141             IOSLAVEn(pIOSState->ui32Module)->FIFOPTR_b.FIFOSIZ = 0x0;
1142             break;
1143         case AM_HAL_IOS_REQ_MAX:
1144             return AM_HAL_STATUS_INVALID_ARG;
1145     }
1146 
1147     return AM_HAL_STATUS_SUCCESS;
1148 }
1149 
1150 //*****************************************************************************
1151 //
1152 //  End the doxygen group
1153 //! @}
1154 //
1155 //*****************************************************************************
1156