1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_lmem_cache.h"
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.lmem"
17 #endif
18
19 #define LMEM_CACHEMODE_WIDTH (2U)
20 #define LMEM_CACHEMODE_MASK_UNIT (0x3U)
21
22 /*******************************************************************************
23 * Code
24 ******************************************************************************/
25
26 /*!
27 * brief Enables/disables the processor code bus cache.
28 * This function enables/disables the cache. The function first invalidates the entire cache
29 * and then enables/disables both the cache and write buffers.
30 *
31 * param base LMEM peripheral base address.
32 * param enable The enable or disable flag.
33 * true - enable the code cache.
34 * false - disable the code cache.
35 */
LMEM_EnableCodeCache(LMEM_Type * base,bool enable)36 void LMEM_EnableCodeCache(LMEM_Type *base, bool enable)
37 {
38 if (enable)
39 {
40 /* First, invalidate the entire cache. */
41 LMEM_CodeCacheInvalidateAll(base);
42
43 /* Now enable the cache. */
44 base->PCCCR |= LMEM_PCCCR_ENCACHE_MASK;
45 }
46 else
47 {
48 /* First, push any modified contents. */
49 LMEM_CodeCachePushAll(base);
50
51 /* Now disable the cache. */
52 base->PCCCR &= ~LMEM_PCCCR_ENCACHE_MASK;
53 }
54 }
55
56 /*!
57 * brief Invalidates the processor code bus cache.
58 * This function invalidates the cache both ways, which means that
59 * it unconditionally clears valid bits and modifies bits of a cache entry.
60 *
61 * param base LMEM peripheral base address.
62 */
LMEM_CodeCacheInvalidateAll(LMEM_Type * base)63 void LMEM_CodeCacheInvalidateAll(LMEM_Type *base)
64 {
65 /* Enables the processor code bus to invalidate all lines in both ways.
66 and Initiate the processor code bus code cache command. */
67 base->PCCCR |= LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_GO_MASK;
68
69 /* Wait until the cache command completes. */
70 while (0U != (base->PCCCR & LMEM_PCCCR_GO_MASK))
71 {
72 ; /* Intentional empty while */
73 }
74
75 /* As a precaution clear the bits to avoid inadvertently re-running this command. */
76 base->PCCCR &= ~(LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK);
77 }
78
79 /*!
80 * brief Pushes all modified lines in the processor code bus cache.
81 * This function pushes all modified lines in both ways in the entire cache.
82 * It pushes a cache entry if it is valid and modified and clears the modified bit. If
83 * the entry is not valid or not modified, leave as is. This action does not clear the valid
84 * bit. A cache push is synonymous with a cache flush.
85 *
86 * param base LMEM peripheral base address.
87 */
LMEM_CodeCachePushAll(LMEM_Type * base)88 void LMEM_CodeCachePushAll(LMEM_Type *base)
89 {
90 /* Enable the processor code bus to push all modified lines. */
91 base->PCCCR |= LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_GO_MASK;
92
93 /* Wait until the cache command completes. */
94 while (0U != (base->PCCCR & LMEM_PCCCR_GO_MASK))
95 {
96 ; /* Intentional empty while */
97 }
98
99 /* As a precaution clear the bits to avoid inadvertently re-running this command. */
100 base->PCCCR &= ~(LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK);
101 }
102
103 /*!
104 * brief Clears the processor code bus cache.
105 * This function clears the entire cache and pushes (flushes) and
106 * invalidates the operation.
107 * Clear - Pushes a cache entry if it is valid and modified, then clears the valid and
108 * modified bits. If the entry is not valid or not modified, clear the valid bit.
109 *
110 * param base LMEM peripheral base address.
111 */
LMEM_CodeCacheClearAll(LMEM_Type * base)112 void LMEM_CodeCacheClearAll(LMEM_Type *base)
113 {
114 /* Push and invalidate all. */
115 base->PCCCR |= LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK |
116 LMEM_PCCCR_GO_MASK;
117
118 /* Wait until the cache command completes. */
119 while (0U != (base->PCCCR & LMEM_PCCCR_GO_MASK))
120 {
121 ; /* Intentional empty while */
122 }
123
124 /* As a precaution clear the bits to avoid inadvertently re-running this command. */
125 base->PCCCR &= ~(LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK);
126 }
127
128 /*FUNCTION**********************************************************************
129 *
130 * Function Name : LMEM_CodeCacheInvalidateLine
131 * Description : This function invalidates a specific line in the Processor Code bus cache.
132 *
133 * This function invalidates a specific line in the cache. The function invalidates a
134 * line in cache based on the physical address passed in by the user.
135 * Invalidate - Unconditionally clear valid and modify bits of a cache entry
136 *
137 *END**************************************************************************/
138 /*!
139 * brief Invalidates a specific line in the processor code bus cache.
140 * This function invalidates a specific line in the cache
141 * based on the physical address passed in by the user.
142 * Invalidate - Unconditionally clears valid and modified bits of a cache entry.
143 *
144 * param base LMEM peripheral base address.
145 * param address The physical address of the cache line. Should be 16-byte aligned address.
146 * If not, it is changed to the 16-byte aligned memory address.
147 */
LMEM_CodeCacheInvalidateLine(LMEM_Type * base,uint32_t address)148 void LMEM_CodeCacheInvalidateLine(LMEM_Type *base, uint32_t address)
149 {
150 uint32_t pccReg = 0;
151
152 /* Set the invalidate by line command and use the physical address. */
153 pccReg =
154 (base->PCCLCR & ~LMEM_PCCLCR_LCMD_MASK) | LMEM_PCCLCR_LCMD(kLMEM_CacheLineInvalidate) | LMEM_PCCLCR_LADSEL_MASK;
155 base->PCCLCR = pccReg;
156
157 /* Set the address and initiate the command. */
158 base->PCCSAR = (address & LMEM_PCCSAR_PHYADDR_MASK) | LMEM_PCCSAR_LGO_MASK;
159
160 /* Wait until the cache command completes. */
161 while (0U != (base->PCCSAR & LMEM_PCCSAR_LGO_MASK))
162 {
163 ; /* Intentional empty while */
164 }
165
166 /* No need to clear this command since future line commands will overwrite
167 the line command field. */
168 }
169
170 /*!
171 * brief Invalidates multiple lines in the processor code bus cache.
172 * This function invalidates multiple lines in the cache
173 * based on the physical address and length in bytes passed in by the
174 * user. If the function detects that the length meets or exceeds half the
175 * cache, the function performs an entire cache invalidate function, which is
176 * more efficient than invalidating the cache line-by-line.
177 * Because the cache consists of two ways and line commands based on the physical address searches both ways,
178 * check half the total amount of cache.
179 * Invalidate - Unconditionally clear valid and modified bits of a cache entry.
180 *
181 * param base LMEM peripheral base address.
182 * param address The physical address of the cache line. Should be 16-byte aligned address.
183 * If not, it is changed to the 16-byte aligned memory address.
184 * param length The length in bytes of the total amount of cache lines.
185 */
LMEM_CodeCacheInvalidateMultiLines(LMEM_Type * base,uint32_t address,uint32_t length)186 void LMEM_CodeCacheInvalidateMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
187 {
188 uint32_t endAddr = address + length;
189 /* Align address to cache line size. */
190 address = address & ~(LMEM_CACHE_LINE_SIZE - 1U);
191 /* If the length exceeds 4KB, invalidate all. */
192 if (length >= LMEM_CACHE_SIZE_ONEWAY)
193 {
194 LMEM_CodeCacheInvalidateAll(base);
195 }
196 else
197 { /* Proceed with multi-line invalidate. */
198 while (address < endAddr)
199 {
200 LMEM_CodeCacheInvalidateLine(base, address);
201 address = address + LMEM_CACHE_LINE_SIZE;
202 }
203 }
204 }
205
206 /*!
207 * brief Pushes a specific modified line in the processor code bus cache.
208 * This function pushes a specific modified line based on the physical address passed in
209 * by the user.
210 * Push - Push a cache entry if it is valid and modified, then clear the modified bit. If the
211 * entry is not valid or not modified, leave as is. This action does not clear the valid
212 * bit. A cache push is synonymous with a cache flush.
213 *
214 * param base LMEM peripheral base address.
215 * param address The physical address of the cache line. Should be 16-byte aligned address.
216 * If not, it is changed to the 16-byte aligned memory address.
217 */
LMEM_CodeCachePushLine(LMEM_Type * base,uint32_t address)218 void LMEM_CodeCachePushLine(LMEM_Type *base, uint32_t address)
219 {
220 uint32_t pccReg = 0;
221
222 /* Set the push by line command. */
223 pccReg = (base->PCCLCR & ~LMEM_PCCLCR_LCMD_MASK) | LMEM_PCCLCR_LCMD(kLMEM_CacheLinePush) | LMEM_PCCLCR_LADSEL_MASK;
224 base->PCCLCR = pccReg;
225
226 /* Set the address and initiate the command. */
227 base->PCCSAR = (address & LMEM_PCCSAR_PHYADDR_MASK) | LMEM_PCCSAR_LGO_MASK;
228
229 /* Wait until the cache command completes. */
230 while (0U != (base->PCCSAR & LMEM_PCCSAR_LGO_MASK))
231 {
232 ; /* Intentional empty while */
233 }
234
235 /* No need to clear this command since future line commands will overwrite
236 the line command field. */
237 }
238
239 /*!
240 * brief Pushes multiple modified lines in the processor code bus cache.
241 * This function pushes multiple modified lines in the cache
242 * based on the physical address and length in bytes passed in by the
243 * user. If the function detects that the length meets or exceeds half of the
244 * cache, the function performs an cache push function, which is
245 * more efficient than pushing the modified lines in the cache line-by-line.
246 * Because the cache consists of two ways and line commands based on the physical address searches both ways,
247 * check half the total amount of cache.
248 * Push - Push a cache entry if it is valid and modified, then clear the modified bit. If
249 * the entry is not valid or not modified, leave as is. This action does not clear the valid
250 * bit. A cache push is synonymous with a cache flush.
251 *
252 * param base LMEM peripheral base address.
253 * param address The physical address of the cache line. Should be 16-byte aligned address.
254 * If not, it is changed to the 16-byte aligned memory address.
255 * param length The length in bytes of the total amount of cache lines.
256 */
LMEM_CodeCachePushMultiLines(LMEM_Type * base,uint32_t address,uint32_t length)257 void LMEM_CodeCachePushMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
258 {
259 uint32_t endAddr = address + length;
260 /* Align address to cache line size. */
261 address = address & ~(LMEM_CACHE_LINE_SIZE - 1U);
262
263 /* If the length exceeds 4KB, push all. */
264 if (length >= LMEM_CACHE_SIZE_ONEWAY)
265 {
266 LMEM_CodeCachePushAll(base);
267 }
268 else
269 { /* Proceed with multi-line push. */
270 while (address < endAddr)
271 {
272 LMEM_CodeCachePushLine(base, address);
273 address = address + LMEM_CACHE_LINE_SIZE;
274 }
275 }
276 }
277
278 /*!
279 * brief Clears a specific line in the processor code bus cache.
280 * This function clears a specific line based on the physical address passed in
281 * by the user.
282 * Clear - Push a cache entry if it is valid and modified, then clear the valid and
283 * modify bits. If entry not valid or not modified, clear the valid bit.
284 *
285 * param base LMEM peripheral base address.
286 * param address The physical address of the cache line. Should be 16-byte aligned address.
287 * If not, it is changed to the 16-byte aligned memory address.
288 */
LMEM_CodeCacheClearLine(LMEM_Type * base,uint32_t address)289 void LMEM_CodeCacheClearLine(LMEM_Type *base, uint32_t address)
290 {
291 uint32_t pccReg = 0;
292
293 /* Set the push by line command. */
294 pccReg = (base->PCCLCR & ~LMEM_PCCLCR_LCMD_MASK) | LMEM_PCCLCR_LCMD(kLMEM_CacheLineClear) | LMEM_PCCLCR_LADSEL_MASK;
295 base->PCCLCR = pccReg;
296
297 /* Set the address and initiate the command. */
298 base->PCCSAR = (address & LMEM_PCCSAR_PHYADDR_MASK) | LMEM_PCCSAR_LGO_MASK;
299
300 /* Wait until the cache command completes. */
301 while (0U != (base->PCCSAR & LMEM_PCCSAR_LGO_MASK))
302 {
303 ; /* Intentional empty while */
304 }
305
306 /* No need to clear this command since future line commands will overwrite
307 the line command field. */
308 }
309
310 /*!
311 * brief Clears multiple lines in the processor code bus cache.
312 * This function clears multiple lines in the cache
313 * based on the physical address and length in bytes passed in by the
314 * user. If the function detects that the length meets or exceeds half the total amount of
315 * cache, the function performs a cache clear function which is
316 * more efficient than clearing the lines in the cache line-by-line.
317 * Because the cache consists of two ways and line commands based on the physical address searches both ways,
318 * check half the total amount of cache.
319 * Clear - Push a cache entry if it is valid and modified, then clear the valid and
320 * modify bits. If entry not valid or not modified, clear the valid bit.
321 *
322 * param base LMEM peripheral base address.
323 * param address The physical address of the cache line. Should be 16-byte aligned address.
324 * If not, it is changed to the 16-byte aligned memory address.
325 * param length The length in bytes of the total amount of cache lines.
326 */
LMEM_CodeCacheClearMultiLines(LMEM_Type * base,uint32_t address,uint32_t length)327 void LMEM_CodeCacheClearMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
328 {
329 uint32_t endAddr = address + length;
330 /* Align address to cache line size. */
331 address = address & ~(LMEM_CACHE_LINE_SIZE - 1U);
332
333 /* If the length exceeds 4KB, clear all. */
334 if (length >= LMEM_CACHE_SIZE_ONEWAY)
335 {
336 LMEM_CodeCacheClearAll(base);
337 }
338 else /* Proceed with multi-line clear. */
339 {
340 while (address < endAddr)
341 {
342 LMEM_CodeCacheClearLine(base, address);
343 address = address + LMEM_CACHE_LINE_SIZE;
344 }
345 }
346 }
347 #if (!defined(FSL_FEATURE_LMEM_SUPPORT_ICACHE_DEMOTE_REMOVE)) || !FSL_FEATURE_LMEM_SUPPORT_ICACHE_DEMOTE_REMOVE
348 /*!
349 * brief Demotes the cache mode of a region in processor code bus cache.
350 * This function allows the user to demote the cache mode of a region within the device's
351 * memory map. Demoting the cache mode reduces the cache function applied to a memory
352 * region from write-back to write-through to non-cacheable. The function checks to see
353 * if the requested cache mode is higher than or equal to the current cache mode, and if
354 * so, returns an error. After a region is demoted, its cache mode can only be raised
355 * by a reset, which returns it to its default state which is the highest cache configure for
356 * each region.
357 * To maintain cache coherency, changes to the cache mode should be completed while the
358 * address space being changed is not being accessed or the cache is disabled. Before a
359 * cache mode change, this function completes a cache clear all command to push and invalidate any
360 * cache entries that may have changed.
361 *
362 * param base LMEM peripheral base address.
363 * param region The desired region to demote of type lmem_cache_region_t.
364 * param cacheMode The new, demoted cache mode of type lmem_cache_mode_t.
365 * return The execution result.
366 * kStatus_Success The cache demote operation is successful.
367 * kStatus_Fail The cache demote operation is failure.
368 */
LMEM_CodeCacheDemoteRegion(LMEM_Type * base,lmem_cache_region_t region,lmem_cache_mode_t cacheMode)369 status_t LMEM_CodeCacheDemoteRegion(LMEM_Type *base, lmem_cache_region_t region, lmem_cache_mode_t cacheMode)
370 {
371 status_t ret = (status_t)kStatus_Success;
372 uint32_t mode = base->PCCRMR;
373 uint32_t shift = LMEM_CACHEMODE_WIDTH * (uint32_t)region; /* Region shift. */
374 uint32_t mask = ((uint32_t)LMEM_CACHEMODE_MASK_UNIT) << shift; /* Region mask. */
375
376 /* If the current cache mode is higher than the requested mode, return error. */
377 if ((uint32_t)cacheMode >= ((mode & mask) >> shift))
378 {
379 ret = (status_t)kStatus_Fail;
380 }
381 else
382 { /* Proceed to demote the region. */
383 LMEM_CodeCacheClearAll(base);
384 base->PCCRMR = (mode & ~mask) | ((uint32_t)cacheMode) << shift;
385 }
386
387 return ret;
388 }
389 #endif /* FSL_FEATURE_LMEM_SUPPORT_ICACHE_DEMOTE_REMOVE */
390
391 #if FSL_FEATURE_LMEM_HAS_SYSTEMBUS_CACHE
392 /*!
393 * brief Enables/disables the processor system bus cache.
394 * This function enables/disables the cache. It first invalidates the entire cache,
395 * then enables /disable both the cache and write buffer.
396 *
397 * param base LMEM peripheral base address.
398 * param The enable or disable flag.
399 * true - enable the system cache.
400 * false - disable the system cache.
401 */
LMEM_EnableSystemCache(LMEM_Type * base,bool enable)402 void LMEM_EnableSystemCache(LMEM_Type *base, bool enable)
403 {
404 if (enable)
405 {
406 /* First, invalidate the entire cache. */
407 LMEM_SystemCacheInvalidateAll(base);
408
409 /* Now enable the cache. */
410 base->PSCCR |= LMEM_PSCCR_ENCACHE_MASK;
411 }
412 else
413 {
414 /* First, push any modified contents. */
415 LMEM_SystemCachePushAll(base);
416
417 /* Now disable the cache. */
418 base->PSCCR &= ~LMEM_PSCCR_ENCACHE_MASK;
419 }
420 }
421
422 /*!
423 * brief Invalidates the processor system bus cache.
424 * This function invalidates the entire cache both ways.
425 * Invalidate - Unconditionally clear valid and modify bits of a cache entry
426 *
427 * param base LMEM peripheral base address.
428 */
LMEM_SystemCacheInvalidateAll(LMEM_Type * base)429 void LMEM_SystemCacheInvalidateAll(LMEM_Type *base)
430 {
431 /* Enables the processor system bus to invalidate all lines in both ways.
432 and Initiate the processor system bus cache command. */
433 base->PSCCR |= LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK | LMEM_PSCCR_GO_MASK;
434
435 /* Wait until the cache command completes */
436 while (0U != (base->PSCCR & LMEM_PSCCR_GO_MASK))
437 {
438 ; /* Intentional empty while */
439 }
440
441 /* As a precaution clear the bits to avoid inadvertently re-running this command. */
442 base->PSCCR &= ~(LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK);
443 }
444
445 /*!
446 * brief Pushes all modified lines in the processor system bus cache.
447 * This function pushes all modified lines in both ways (the entire cache).
448 * Push - Push a cache entry if it is valid and modified, then clear the modify bit. If
449 * the entry is not valid or not modified, leave as is. This action does not clear the valid
450 * bit. A cache push is synonymous with a cache flush.
451 *
452 * param base LMEM peripheral base address.
453 */
LMEM_SystemCachePushAll(LMEM_Type * base)454 void LMEM_SystemCachePushAll(LMEM_Type *base)
455 {
456 /* Enable the processor system bus to push all modified lines. */
457 base->PSCCR |= LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_GO_MASK;
458
459 /* Wait until the cache command completes. */
460 while (0U != (base->PSCCR & LMEM_PSCCR_GO_MASK))
461 {
462 ; /* Intentional empty while */
463 }
464
465 /* As a precaution clear the bits to avoid inadvertently re-running this command. */
466 base->PSCCR &= ~(LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK);
467 }
468
469 /*!
470 * brief Clears the entire processor system bus cache.
471 * This function clears the entire cache, which is a push (flush) and
472 * invalidate operation.
473 * Clear - Push a cache entry if it is valid and modified, then clear the valid and
474 * modify bits. If the entry is not valid or not modified, clear the valid bit.
475 *
476 * param base LMEM peripheral base address.
477 */
LMEM_SystemCacheClearAll(LMEM_Type * base)478 void LMEM_SystemCacheClearAll(LMEM_Type *base)
479 {
480 /* Push and invalidate all. */
481 base->PSCCR |= LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK |
482 LMEM_PSCCR_GO_MASK;
483
484 /* Wait until the cache command completes. */
485 while (0U != (base->PSCCR & LMEM_PSCCR_GO_MASK))
486 {
487 ; /* Intentional empty while */
488 }
489
490 /* As a precaution clear the bits to avoid inadvertently re-running this command. */
491 base->PSCCR &= ~(LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK);
492 }
493
494 /*!
495 * brief Invalidates a specific line in the processor system bus cache.
496 * This function invalidates a specific line in the cache
497 * based on the physical address passed in by the user.
498 * Invalidate - Unconditionally clears valid and modify bits of a cache entry.
499 *
500 * param base LMEM peripheral base address. Should be 16-byte aligned address.
501 * If not, it is changed to the 16-byte aligned memory address.
502 * param address The physical address of the cache line.
503 */
LMEM_SystemCacheInvalidateLine(LMEM_Type * base,uint32_t address)504 void LMEM_SystemCacheInvalidateLine(LMEM_Type *base, uint32_t address)
505 {
506 uint32_t pscReg = 0U;
507
508 /* Set the invalidate by line command and use the physical address. */
509 pscReg =
510 (base->PSCLCR & ~LMEM_PSCLCR_LCMD_MASK) | LMEM_PSCLCR_LCMD(kLMEM_CacheLineInvalidate) | LMEM_PSCLCR_LADSEL_MASK;
511 base->PSCLCR = pscReg;
512
513 /* Set the address and initiate the command. */
514 base->PSCSAR = (address & LMEM_PSCSAR_PHYADDR_MASK) | LMEM_PSCSAR_LGO_MASK;
515
516 /* Wait until the cache command completes. */
517 while (0U != (base->PSCSAR & LMEM_PSCSAR_LGO_MASK))
518 {
519 ; /* Intentional empty while */
520 }
521
522 /* No need to clear this command since future line commands will overwrite
523 the line command field. */
524 }
525
526 /*!
527 * brief Invalidates multiple lines in the processor system bus cache.
528 * This function invalidates multiple lines in the cache
529 * based on the physical address and length in bytes passed in by the
530 * user. If the function detects that the length meets or exceeds half of the
531 * cache, the function performs an entire cache invalidate function (which is
532 * more efficient than invalidating the cache line-by-line).
533 * Because the cache consists of two ways and line commands based on the physical address searches both ways,
534 * check half the total amount of cache.
535 * Invalidate - Unconditionally clear valid and modify bits of a cache entry
536 *
537 * param base LMEM peripheral base address.
538 * param address The physical address of the cache line. Should be 16-byte aligned address.
539 * If not, it is changed to the 16-byte aligned memory address.
540 * param length The length in bytes of the total amount of cache lines.
541 */
LMEM_SystemCacheInvalidateMultiLines(LMEM_Type * base,uint32_t address,uint32_t length)542 void LMEM_SystemCacheInvalidateMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
543 {
544 uint32_t endAddr = address + length;
545 uint32_t tempAddress = address;
546 tempAddress = tempAddress & ~(LMEM_CACHE_LINE_SIZE - 1U); /* Align address to cache line size */
547
548 /* If the length exceeds 4KB, invalidate all. */
549 if (length >= LMEM_CACHE_SIZE_ONEWAY)
550 {
551 LMEM_SystemCacheInvalidateAll(base);
552 }
553 else /* Proceed with multi-line invalidate. */
554 {
555 while (tempAddress < endAddr)
556 {
557 LMEM_SystemCacheInvalidateLine(base, tempAddress);
558 tempAddress = tempAddress + LMEM_CACHE_LINE_SIZE;
559 }
560 }
561 }
562
563 /*!
564 * brief Pushes a specific modified line in the processor system bus cache.
565 * This function pushes a specific modified line based on the physical address passed in
566 * by the user.
567 * Push - Push a cache entry if it is valid and modified, then clear the modify bit. If
568 * the entry is not valid or not modified, leave as is. This action does not clear the valid
569 * bit. A cache push is synonymous with a cache flush.
570 *
571 * param base LMEM peripheral base address.
572 * param address The physical address of the cache line. Should be 16-byte aligned address.
573 * If not, it is changed to the 16-byte aligned memory address.
574 */
LMEM_SystemCachePushLine(LMEM_Type * base,uint32_t address)575 void LMEM_SystemCachePushLine(LMEM_Type *base, uint32_t address)
576 {
577 uint32_t pscReg = 0U;
578
579 /* Set the push by line command. */
580 pscReg = (base->PSCLCR & ~LMEM_PSCLCR_LCMD_MASK) | LMEM_PSCLCR_LCMD(kLMEM_CacheLinePush) | LMEM_PSCLCR_LADSEL_MASK;
581 base->PSCLCR = pscReg;
582
583 /* Set the address and initiate the command. */
584 base->PSCSAR = (address & LMEM_PSCSAR_PHYADDR_MASK) | LMEM_PSCSAR_LGO_MASK;
585
586 /* Wait until the cache command completes. */
587 while (0U != (base->PSCSAR & LMEM_PSCSAR_LGO_MASK))
588 {
589 ; /* Intentional empty while */
590 }
591
592 /* No need to clear this command since future line commands will overwrite
593 the line command field. */
594 }
595
596 /*!
597 * brief Pushes multiple modified lines in the processor system bus cache.
598 * This function pushes multiple modified lines in the cache
599 * based on the physical address and length in bytes passed in by the
600 * user. If the function detects that the length meets or exceeds half of the
601 * cache, the function performs an entire cache push function (which is
602 * more efficient than pushing the modified lines in the cache line-by-line).
603 * Because the cache consists of two ways and line commands based on the physical address searches both ways,
604 * check half the total amount of cache.
605 * Push - Push a cache entry if it is valid and modified, then clear the modify bit. If
606 * the entry is not valid or not modified, leave as is. This action does not clear the valid
607 * bit. A cache push is synonymous with a cache flush.
608 *
609 * param base LMEM peripheral base address.
610 * param address The physical address of the cache line. Should be 16-byte aligned address.
611 * If not, it is changed to the 16-byte aligned memory address.
612 * param length The length in bytes of the total amount of cache lines.
613 */
LMEM_SystemCachePushMultiLines(LMEM_Type * base,uint32_t address,uint32_t length)614 void LMEM_SystemCachePushMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
615 {
616 uint32_t endAddr = address + length;
617 uint32_t tempAddress = address;
618 tempAddress = tempAddress & ~(LMEM_CACHE_LINE_SIZE - 1U); /* Align address to cache line size. */
619
620 /* If the length exceeds 4KB, push all. */
621 if (length >= LMEM_CACHE_SIZE_ONEWAY)
622 {
623 LMEM_SystemCachePushAll(base);
624 }
625 else
626 { /* Proceed with multi-line push. */
627 while (tempAddress < endAddr)
628 {
629 LMEM_SystemCachePushLine(base, tempAddress);
630 tempAddress = tempAddress + LMEM_CACHE_LINE_SIZE;
631 }
632 }
633 }
634
635 /*!
636 * brief Clears a specific line in the processor system bus cache.
637 * This function clears a specific line based on the physical address passed in
638 * by the user.
639 * Clear - Push a cache entry if it is valid and modified, then clear the valid and
640 * modify bits. If the entry is not valid or not modified, clear the valid bit.
641 *
642 * param base LMEM peripheral base address.
643 * param address The physical address of the cache line. Should be 16-byte aligned address.
644 * If not, it is changed to the 16-byte aligned memory address.
645 */
LMEM_SystemCacheClearLine(LMEM_Type * base,uint32_t address)646 void LMEM_SystemCacheClearLine(LMEM_Type *base, uint32_t address)
647 {
648 uint32_t pscReg = 0U;
649
650 /* Set the push by line command. */
651 pscReg = (base->PSCLCR & ~LMEM_PSCLCR_LCMD_MASK) | LMEM_PSCLCR_LCMD(kLMEM_CacheLineClear) | LMEM_PSCLCR_LADSEL_MASK;
652 base->PSCLCR = pscReg;
653
654 /* Set the address and initiate the command. */
655 base->PSCSAR = (address & LMEM_PSCSAR_PHYADDR_MASK) | LMEM_PSCSAR_LGO_MASK;
656
657 /* Wait until the cache command completes. */
658 while (0U != (base->PSCSAR & LMEM_PSCSAR_LGO_MASK))
659 {
660 ; /* Intentional empty while */
661 }
662
663 /* No need to clear this command since future line commands will overwrite
664 the line command field. */
665 }
666
667 /*!
668 * brief Clears multiple lines in the processor system bus cache.
669 * This function clears multiple lines in the cache
670 * based on the physical address and length in bytes passed in by the
671 * user. If the function detects that the length meets or exceeds half of the
672 * cache, the function performs an entire cache clear function (which is
673 * more efficient than clearing the lines in the cache line-by-line).
674 * Because the cache consists of two ways and line commands based on the physical address searches both ways,
675 * check half the total amount of cache.
676 * Clear - Push a cache entry if it is valid and modified, then clear the valid and
677 * modify bits. If the entry is not valid or not modified, clear the valid bit.
678 *
679 * param base LMEM peripheral base address.
680 * param address The physical address of the cache line. Should be 16-byte aligned address.
681 * If not, it is changed to the 16-byte aligned memory address.
682 * param length The length in bytes of the total amount of cache lines.
683 */
LMEM_SystemCacheClearMultiLines(LMEM_Type * base,uint32_t address,uint32_t length)684 void LMEM_SystemCacheClearMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
685 {
686 uint32_t endAddr = address + length;
687 uint32_t tempAddress = address;
688 tempAddress = tempAddress & ~(LMEM_CACHE_LINE_SIZE - 1U); /* Align address to cache line size. */
689
690 /* If the length exceeds 4KB, clear all. */
691 if (length >= LMEM_CACHE_SIZE_ONEWAY)
692 {
693 LMEM_SystemCacheClearAll(base);
694 }
695 else /* Proceed with multi-line clear. */
696 {
697 while (tempAddress < endAddr)
698 {
699 LMEM_SystemCacheClearLine(base, tempAddress);
700 tempAddress = tempAddress + LMEM_CACHE_LINE_SIZE;
701 }
702 }
703 }
704
705 /*!
706 * brief Demotes the cache mode of a region in the processor system bus cache.
707 * This function allows the user to demote the cache mode of a region within the device's
708 * memory map. Demoting the cache mode reduces the cache function applied to a memory
709 * region from write-back to write-through to non-cacheable. The function checks to see
710 * if the requested cache mode is higher than or equal to the current cache mode, and if
711 * so, returns an error. After a region is demoted, its cache mode can only be raised
712 * by a reset, which returns it to its default state which is the highest cache configure
713 * for each region.
714 * To maintain cache coherency, changes to the cache mode should be completed while the
715 * address space being changed is not being accessed or the cache is disabled. Before a
716 * cache mode change, this function completes a cache clear all command to push and invalidate any
717 * cache entries that may have changed.
718 *
719 * param base LMEM peripheral base address.
720 * param region The desired region to demote of type lmem_cache_region_t.
721 * param cacheMode The new, demoted cache mode of type lmem_cache_mode_t.
722 * return The execution result.
723 * kStatus_Success The cache demote operation is successful.
724 * kStatus_Fail The cache demote operation is failure.
725 */
LMEM_SystemCacheDemoteRegion(LMEM_Type * base,lmem_cache_region_t region,lmem_cache_mode_t cacheMode)726 status_t LMEM_SystemCacheDemoteRegion(LMEM_Type *base, lmem_cache_region_t region, lmem_cache_mode_t cacheMode)
727 {
728 status_t ret = kStatus_Success;
729 uint32_t mode = base->PSCRMR;
730 uint32_t shift = LMEM_CACHEMODE_WIDTH * (uint32_t)region; /* Region shift. */
731 uint32_t mask; /* Region mask. */
732 uint32_t temp = LMEM_CACHEMODE_MASK_UNIT;
733
734 mask = temp << shift;
735
736 /* If the current cache mode is higher than the requested mode, return error. */
737 if ((uint32_t)cacheMode >= ((mode & mask) >> shift))
738 {
739 ret = kStatus_Fail;
740 }
741 else
742 { /* Proceed to demote the region. */
743 LMEM_SystemCacheClearAll(base);
744 base->PSCRMR = (mode & ~mask) | (((uint32_t)cacheMode) << shift);
745 }
746
747 return ret;
748 }
749 #endif /* FSL_FEATURE_LMEM_HAS_SYSTEMBUS_CACHE */
750