1 //*****************************************************************************
2 //
3 //! @file am_hal_cachectrl.c
4 //!
5 //! @brief Functions for interfacing with the CACHE controller.
6 //!
7 //! @addtogroup cachectrl4_4p CACHE - Cache Control
8 //! @ingroup apollo4p_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 stable-7da8bae71f of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 //*****************************************************************************
53 //
54 //!  Default settings for the cache.
55 //
56 //*****************************************************************************
57 const am_hal_cachectrl_config_t am_hal_cachectrl_defaults =
58 {
59     .bLRU                       = 0,
60     .eDescript                  = AM_HAL_CACHECTRL_DESCR_1WAY_128B_4096E,
61     .eMode                      = AM_HAL_CACHECTRL_CONFIG_MODE_INSTR_DATA,
62 };
63 
64 //*****************************************************************************
65 //
66 //!  Default settings for the DAXI.
67 //!  @note CAUTION: When changing this, also update gDaxiConfig accordingly
68 //
69 //*****************************************************************************
70 const am_hal_daxi_config_t am_hal_daxi_defaults =
71 {
72     .bDaxiPassThrough         = false,
73     .bAgingSEnabled            = true,
74     .eAgingCounter            = AM_HAL_DAXI_CONFIG_AGING_4,
75     .eNumBuf                  = AM_HAL_DAXI_CONFIG_NUMBUF_32,
76     .eNumFreeBuf              = AM_HAL_DAXI_CONFIG_NUMFREEBUF_3,
77 };
78 
79 //*****************************************************************************
80 //
81 //! Initialize gDaxiConfig as default
82 //
83 //*****************************************************************************
84 am_hal_daxi_config_t gDaxiConfig =
85 {
86     .bDaxiPassThrough         = false,
87     .bAgingSEnabled            = true,
88     .eAgingCounter            = AM_HAL_DAXI_CONFIG_AGING_4,
89     .eNumBuf                  = AM_HAL_DAXI_CONFIG_NUMBUF_32,
90     .eNumFreeBuf              = AM_HAL_DAXI_CONFIG_NUMFREEBUF_3,
91 };
92 
93 static void
daxi_flush_invalidate(bool bFlush)94 daxi_flush_invalidate(bool bFlush)
95 {
96     if (CPU->DAXICFG_b.DAXIPASSTHROUGH)
97     {
98         return;
99     }
100 
101     //
102     // Call DSB
103     //
104     __DSB();
105 
106     if (bFlush)
107     {
108         //
109         // Call DAXI Flush
110         //
111         CPU->DAXICTRL_b.DAXIFLUSHWRITE = 1;
112 
113         //
114         // APB_SYNC
115         //
116         am_hal_sysctrl_sysbus_write_flush();
117 
118         while ( !CPU->DAXICTRL_b.DAXIREADY );
119     }
120 
121     //
122     // Call DAXI Invalidate
123     //
124     CPU->DAXICTRL_b.DAXIINVALIDATE = 1;
125 
126     //
127     // APB_SYNC
128     //
129     am_hal_sysctrl_sysbus_write_flush();
130 
131 } // daxi_flush_invalidate()
132 
133 //*****************************************************************************
134 //
135 // Write flush - This function will return once all queued write
136 // operations have completed, thereby guaranteeing that all
137 // writes have been flushed.
138 // This works across all the buses - AXI and APB
139 //
140 //*****************************************************************************
141 static void
daxi_flush_complete(void)142 daxi_flush_complete(void)
143 {
144     AM_CRITICAL_BEGIN
145     daxi_flush_invalidate(true);
146     AM_CRITICAL_END
147 
148 } // daxi_flush_complete()
149 
150 //*****************************************************************************
151 //
152 //  Configure the cache with given and recommended settings, but do not enable.
153 //
154 //*****************************************************************************
155 uint32_t
am_hal_cachectrl_config(const am_hal_cachectrl_config_t * psConfig)156 am_hal_cachectrl_config(const am_hal_cachectrl_config_t *psConfig)
157 {
158     //
159     // In the case where cache is currently enabled, we need to gracefully
160     // bow out of that configuration before reconfiguring.  The best way to
161     // accomplish that is to shut down the ID bits, leaving the cache enabled.
162     // Once the instr and data caches have been disabled, we can safely set
163     // any new configuration, including disabling the controller.
164     //
165     AM_CRITICAL_BEGIN
166     CPU->CACHECFG &=
167         ~(CPU_CACHECFG_DENABLE_Msk  |
168           CPU_CACHECFG_IENABLE_Msk);
169     AM_CRITICAL_END
170 
171     CPU->CACHECFG =
172         _VAL2FLD(CPU_CACHECFG_ENABLE, 0)                              |
173         _VAL2FLD(CPU_CACHECFG_CLKGATE, 1)                             |
174         _VAL2FLD(CPU_CACHECFG_LS, 0)                                  |
175         _VAL2FLD(CPU_CACHECFG_DATACLKGATE, 1)                         |
176         _VAL2FLD(CPU_CACHECFG_ENABLEMONITOR, 0)                       |
177         _VAL2FLD(CPU_CACHECFG_LRU, psConfig->bLRU)                    |
178         _VAL2FLD(CPU_CACHECFG_CONFIG, psConfig->eDescript)            |
179         ((psConfig->eMode << CPU_CACHECFG_IENABLE_Pos) &
180             (CPU_CACHECFG_DENABLE_Msk   |
181              CPU_CACHECFG_IENABLE_Msk));
182 
183     return AM_HAL_STATUS_SUCCESS;
184 
185 } // am_hal_cachectrl_config()
186 
187 //*****************************************************************************
188 //
189 //  Enable the cache.
190 //
191 //*****************************************************************************
192 uint32_t
am_hal_cachectrl_enable(void)193 am_hal_cachectrl_enable(void)
194 {
195     //
196     // Enable the cache
197     //
198     CPU->CACHECFG_b.ENABLE      = 1;
199     CPU->CACHECTRL_b.INVALIDATE = 1;
200 
201     return AM_HAL_STATUS_SUCCESS;
202 
203 } // am_hal_cachectrl_enable()
204 
205 //*****************************************************************************
206 //
207 //  Disable the cache.
208 //
209 //*****************************************************************************
210 uint32_t
am_hal_cachectrl_disable(void)211 am_hal_cachectrl_disable(void)
212 {
213     //
214     // Shut down as gracefully as possible.
215     // Disable the I/D cache enable bits first to allow a little time
216     // for any in-flight transactions to hand off to the line buffer.
217     // Then clear the enable.
218     //
219     AM_CRITICAL_BEGIN
220     CPU->CACHECFG &= ~(_VAL2FLD(CPU_CACHECFG_IENABLE, 1) |
221                        _VAL2FLD(CPU_CACHECFG_DENABLE, 1));
222     CPU->CACHECFG &= ~_VAL2FLD(CPU_CACHECFG_ENABLE, 1);
223     AM_CRITICAL_END
224 
225     return AM_HAL_STATUS_SUCCESS;
226 } // am_hal_cachectrl_disable()
227 
228 //*****************************************************************************
229 //
230 //  Select the cache configuration type.
231 //
232 //*****************************************************************************
233 uint32_t
am_hal_cachectrl_control(am_hal_cachectrl_control_e eControl,void * pArgs)234 am_hal_cachectrl_control(am_hal_cachectrl_control_e eControl, void *pArgs)
235 {
236     //
237     // All fields in the CACHECTRL register are write-only or read-only.
238     // A write to CACHECTRL acts as a mask-set.  That is, only the bits
239     // written as '1' have an effect, any bits written as '0' are unaffected.
240     //
241     // Important note - setting of an enable and disable simultanously has
242     // unpredicable results.
243     //
244     switch ( eControl )
245     {
246         case AM_HAL_CACHECTRL_CONTROL_MRAM_CACHE_INVALIDATE:
247         {
248             CPU->CACHECTRL = CPU_CACHECTRL_INVALIDATE_Msk;
249             am_hal_sysctrl_sysbus_write_flush();
250             return am_hal_delay_us_status_change(100, (uint32_t)&CPU->CACHECTRL,
251                                                  CPU_CACHECTRL_CACHEREADY_Msk,
252                                                  CPU_CACHECTRL_CACHEREADY_Msk);
253         }
254 
255         case AM_HAL_CACHECTRL_CONTROL_STATISTICS_RESET:
256             if ( !_FLD2VAL(CPU_CACHECFG_ENABLEMONITOR, CPU->CACHECFG) )
257             {
258                 //
259                 // The monitor must be enabled for the reset to have any affect.
260                 //
261                 return AM_HAL_STATUS_INVALID_OPERATION;
262             }
263             else
264             {
265                 CPU->CACHECTRL = CPU_CACHECTRL_RESETSTAT_Msk;
266                 am_hal_sysctrl_sysbus_write_flush();
267             }
268             break;
269 
270         case AM_HAL_CACHECTRL_CONTROL_MONITOR_ENABLE:
271             AM_CRITICAL_BEGIN
272             CPU->CACHECFG |= CPU_CACHECFG_ENABLEMONITOR_Msk;
273             am_hal_sysctrl_sysbus_write_flush();
274             AM_CRITICAL_END
275             break;
276 
277         case AM_HAL_CACHECTRL_CONTROL_MONITOR_DISABLE:
278             AM_CRITICAL_BEGIN
279             CPU->CACHECFG &= ~CPU_CACHECFG_ENABLEMONITOR_Msk;
280             am_hal_sysctrl_sysbus_write_flush();
281             AM_CRITICAL_END
282             break;
283 
284         case AM_HAL_CACHECTRL_CONTROL_NC_CFG:
285         {
286             if ( pArgs == NULL )
287             {
288                 return AM_HAL_STATUS_INVALID_ARG;
289             }
290 
291             am_hal_cachectrl_nc_cfg_t *pNcCfg;
292             pNcCfg = (am_hal_cachectrl_nc_cfg_t *)pArgs;
293 #ifndef AM_HAL_DISABLE_API_VALIDATION
294             //
295             // Make sure the addresses are valid
296             //
297             if ((pNcCfg->ui32StartAddr & ~CPU_NCR0START_ADDR_Msk) ||
298                 (pNcCfg->ui32EndAddr & ~CPU_NCR0START_ADDR_Msk))
299             {
300                 return AM_HAL_STATUS_INVALID_ARG;
301             }
302 #endif // AM_HAL_DISABLE_API_VALIDATION
303             if (pNcCfg->eNCRegion == AM_HAL_CACHECTRL_NCR0)
304             {
305                 CPU->NCR0START = pNcCfg->ui32StartAddr;
306                 CPU->NCR0END   = pNcCfg->ui32EndAddr;
307                 CPU->CACHECFG_b.NC0ENABLE = pNcCfg->bEnable;
308             }
309             else if (pNcCfg->eNCRegion == AM_HAL_CACHECTRL_NCR1)
310             {
311                 CPU->NCR1START = pNcCfg->ui32StartAddr;
312                 CPU->NCR1END   = pNcCfg->ui32EndAddr;
313                 CPU->CACHECFG_b.NC1ENABLE = pNcCfg->bEnable;
314             }
315 #ifndef AM_HAL_DISABLE_API_VALIDATION
316             else
317             {
318                 return AM_HAL_STATUS_INVALID_ARG;
319             }
320 #endif // AM_HAL_DISABLE_API_VALIDATION
321             am_hal_sysctrl_sysbus_write_flush();
322             return AM_HAL_STATUS_SUCCESS;
323         }
324 
325         default:
326             return AM_HAL_STATUS_INVALID_ARG;
327     }
328 
329     return AM_HAL_STATUS_SUCCESS;
330 
331 } // am_hal_cachectrl_control()
332 
333 //*****************************************************************************
334 //
335 //  Cache controller status function
336 //
337 //*****************************************************************************
338 uint32_t
am_hal_cachectrl_status_get(am_hal_cachectrl_status_t * psStatus)339 am_hal_cachectrl_status_get(am_hal_cachectrl_status_t *psStatus)
340 {
341     if ( psStatus == NULL )
342     {
343         return AM_HAL_STATUS_INVALID_ARG;
344     }
345 
346     //
347     // Cache Ready Status
348     //
349     psStatus->bCacheReady = CPU->CACHECTRL_b.CACHEREADY;
350 
351     return AM_HAL_STATUS_SUCCESS;
352 
353 } // am_hal_cachectrl_status_get()
354 
355 //*****************************************************************************
356 //
357 //  Configure the DAXI with given settings.
358 //  psConfig of NULL implies DAXI in pass through mode
359 //
360 //*****************************************************************************
361 uint32_t
am_hal_daxi_config(const am_hal_daxi_config_t * psConfig)362 am_hal_daxi_config(const am_hal_daxi_config_t *psConfig)
363 {
364     AM_CRITICAL_BEGIN
365     am_hal_sysctrl_bus_write_flush();
366     if (psConfig)
367     {
368         CPU->DAXICFG =
369             _VAL2FLD(CPU_DAXICFG_FLUSHLEVEL, psConfig->eNumFreeBuf)         |
370             _VAL2FLD(CPU_DAXICFG_AGINGSENABLE, psConfig->bAgingSEnabled)    |
371             _VAL2FLD(CPU_DAXICFG_DAXIPASSTHROUGH, 0)                        |
372             _VAL2FLD(CPU_DAXICFG_BUFFERENABLE, psConfig->eNumBuf)           |
373             _VAL2FLD(CPU_DAXICFG_AGINGCOUNTER, psConfig->eAgingCounter)     |
374             _VAL2FLD(CPU_DAXICFG_MRUGROUPLEVEL, CPU_DAXICFG_MRUGROUPLEVEL_MAX);
375         gDaxiConfig = *psConfig;
376     }
377     else
378     {
379         //
380         // Need to set config a certain way even for PassThrough
381         //
382         CPU->DAXICFG =
383             _VAL2FLD(CPU_DAXICFG_FLUSHLEVEL, 0)         |
384             _VAL2FLD(CPU_DAXICFG_AGINGSENABLE, 1)       |
385             _VAL2FLD(CPU_DAXICFG_DAXIPASSTHROUGH, 1)    |
386             _VAL2FLD(CPU_DAXICFG_BUFFERENABLE, 0)       |
387             _VAL2FLD(CPU_DAXICFG_AGINGCOUNTER, 0)       |
388             _VAL2FLD(CPU_DAXICFG_MRUGROUPLEVEL, 0);
389     }
390 
391     //
392     // APB_SYNC
393     //
394     am_hal_sysctrl_sysbus_write_flush();
395     AM_CRITICAL_END
396 
397     return AM_HAL_STATUS_SUCCESS;
398 }
399 
400 //*****************************************************************************
401 //
402 //  Misc. DAXI controls.
403 //
404 //*****************************************************************************
405 uint32_t
am_hal_daxi_control(am_hal_daxi_control_e eControl,void * pArgs)406 am_hal_daxi_control(am_hal_daxi_control_e eControl, void *pArgs)
407 {
408     switch ( eControl )
409     {
410         case AM_HAL_DAXI_CONTROL_FLUSH:
411             daxi_flush_complete();
412             break;
413         case AM_HAL_DAXI_CONTROL_INVALIDATE:
414             daxi_flush_invalidate(false);
415             break;
416         case AM_HAL_DAXI_CONTROL_DISABLE:
417             am_hal_daxi_config(NULL);
418             break;
419         case AM_HAL_DAXI_CONTROL_ENABLE:
420             am_hal_daxi_config(&gDaxiConfig);
421             break;
422         default:
423             return AM_HAL_STATUS_INVALID_ARG;
424     }
425     return AM_HAL_STATUS_SUCCESS;
426 }
427 
428 //*****************************************************************************
429 //
430 //  Get the current DAXI settings.
431 //
432 //*****************************************************************************
433 uint32_t
am_hal_daxi_config_get(am_hal_daxi_config_t * psConfig)434 am_hal_daxi_config_get(am_hal_daxi_config_t *psConfig)
435 {
436 #ifndef AM_HAL_DISABLE_API_VALIDATION
437     if (!psConfig)
438     {
439         return AM_HAL_STATUS_INVALID_ARG;
440     }
441 #endif
442     psConfig->bDaxiPassThrough = _FLD2VAL(CPU_DAXICFG_DAXIPASSTHROUGH, CPU->DAXICFG);
443     psConfig->bAgingSEnabled   = _FLD2VAL(CPU_DAXICFG_AGINGSENABLE, CPU->DAXICFG);
444     psConfig->eAgingCounter    = (am_hal_daxi_config_aging_e)_FLD2VAL(CPU_DAXICFG_AGINGCOUNTER, CPU->DAXICFG);
445     psConfig->eNumBuf          = (am_hal_daxi_config_numbuf_e)_FLD2VAL(CPU_DAXICFG_BUFFERENABLE, CPU->DAXICFG);
446     psConfig->eNumFreeBuf      = (am_hal_daxi_config_numfreebuf_e)_FLD2VAL(CPU_DAXICFG_FLUSHLEVEL, CPU->DAXICFG);
447     return AM_HAL_STATUS_SUCCESS;
448 }
449 
450 //*****************************************************************************
451 //
452 //  Get the current DAXI status is complete.
453 //
454 //*****************************************************************************
am_hal_daxi_status_get(am_hal_daxi_status_t * pStatus)455 uint32_t am_hal_daxi_status_get(am_hal_daxi_status_t *pStatus)
456 {
457     //
458     // return the DAXIREADY status.
459     //
460     pStatus->bDaxiReady = CPU->DAXICTRL_b.DAXIREADY;
461 
462     //
463     // return the DAXISHARED status.
464     //
465     pStatus->bDaxiShared = CPU->DAXICTRL_b.DAXISHARED;
466 
467     return AM_HAL_STATUS_SUCCESS;
468 }
469 //*****************************************************************************
470 //
471 // End Doxygen group.
472 //! @}
473 //
474 //*****************************************************************************
475