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