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