1 /*
2  * Copyright 2022 - 2023 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_cache.h"
9 /*******************************************************************************
10  * Definitions
11  ******************************************************************************/
12 
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.cache_xcache"
16 #endif
17 
18 #if (FSL_FEATURE_SOC_XCACHE_COUNT > 0)
19 /*******************************************************************************
20  * Variables
21  ******************************************************************************/
22 /* Array of XCACHE peripheral base address. */
23 static XCACHE_Type *const s_xcachectrlBases[] = XCACHE_BASE_PTRS;
24 
25 /* Array of XCACHE physical memory base address. */
26 static uint32_t const s_xcachePhymemBases[] = XCACHE_PHYMEM_BASES;
27 /* Array of XCACHE physical memory size. */
28 static uint32_t const s_xcachePhymemSizes[] = XCACHE_PHYMEM_SIZES;
29 
30 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
31 #ifdef XCACHE_CLOCKS
32 /* Array of XCACHE clock name. */
33 static const clock_ip_name_t s_xcacheClocks[] = XCACHE_CLOCKS;
34 #endif
35 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
36 
37 /*******************************************************************************
38  * Code
39  ******************************************************************************/
40 /*!
41  * brief Returns an instance number given physical memory address.
42  *
43  * param address The physical memory address.
44  * return XCACHE instance number starting from 0.
45  */
XCACHE_GetInstanceByAddr(uint32_t address)46 uint32_t XCACHE_GetInstanceByAddr(uint32_t address)
47 {
48     uint32_t i;
49 
50     for (i = 0; i < ARRAY_SIZE(s_xcachectrlBases); i++)
51     {
52         if ((address >= s_xcachePhymemBases[i]) &&
53             (address < (s_xcachePhymemBases[i] + s_xcachePhymemSizes[i] - 0x01U)))
54         {
55             break;
56         }
57     }
58 
59     return i;
60 }
61 
62 /*!
63  * brief Enables the cache.
64  *
65  */
XCACHE_EnableCache(XCACHE_Type * base)66 void XCACHE_EnableCache(XCACHE_Type *base)
67 {
68     /* Return if XCACHE is already enabled */
69     if ((base->CCR & XCACHE_CCR_ENCACHE_MASK) == 0x00U)
70     {
71         /* First, invalidate the entire cache. */
72         XCACHE_InvalidateCache(base);
73 
74         /* Now enable the cache. */
75         base->CCR |= XCACHE_CCR_ENCACHE_MASK;
76     }
77 }
78 
79 /*!
80  * brief Disables the cache.
81  *
82  */
XCACHE_DisableCache(XCACHE_Type * base)83 void XCACHE_DisableCache(XCACHE_Type *base)
84 {
85     if (XCACHE_CCR_ENCACHE_MASK == (XCACHE_CCR_ENCACHE_MASK & base->CCR))
86     {
87         /* First, push any modified contents. */
88         XCACHE_CleanCache(base);
89 
90         /* Now disable the cache. */
91         base->CCR &= ~XCACHE_CCR_ENCACHE_MASK;
92     }
93 }
94 
95 /*!
96  * brief Invalidates the cache.
97  *
98  */
XCACHE_InvalidateCache(XCACHE_Type * base)99 void XCACHE_InvalidateCache(XCACHE_Type *base)
100 {
101     /* Invalidate all lines in both ways and initiate the cache command. */
102     base->CCR |= XCACHE_CCR_INVW0_MASK | XCACHE_CCR_INVW1_MASK | XCACHE_CCR_GO_MASK;
103 
104     /* Wait until the cache command completes. */
105     while ((base->CCR & XCACHE_CCR_GO_MASK) != 0x00U)
106     {
107     }
108 
109     /* As a precaution clear the bits to avoid inadvertently re-running this command. */
110     base->CCR &= ~(XCACHE_CCR_INVW0_MASK | XCACHE_CCR_INVW1_MASK);
111 }
112 
113 /*!
114  * brief Invalidates cache by range.
115  *
116  * param address The physical address of cache.
117  * param size_byte size of the memory to be invalidated, should be larger than 0,
118  * better to align to size of cache line.
119  * note Address and size should be aligned to "L1CODCACHE_LINESIZE_BYTE".
120  * The startAddr here will be forced to align to XCACHE_LINESIZE_BYTE if
121  * startAddr is not aligned. For the size_byte, application should make sure the
122  * alignment or make sure the right operation order if the size_byte is not aligned.
123  */
XCACHE_InvalidateCacheByRange(uint32_t address,uint32_t size_byte)124 void XCACHE_InvalidateCacheByRange(uint32_t address, uint32_t size_byte)
125 {
126     if (size_byte > 0UL)
127     {
128         uint32_t endAddr = address + size_byte - 0x01U;
129         uint32_t pccReg  = 0;
130         /* Align address to cache line size. */
131         uint32_t startAddr = address & ~((uint32_t)XCACHE_LINESIZE_BYTE - 1U);
132         uint32_t instance  = XCACHE_GetInstanceByAddr(address);
133         uint32_t endLim;
134         XCACHE_Type *base;
135 
136         if (instance >= ARRAY_SIZE(s_xcachectrlBases))
137         {
138             return;
139         }
140         base    = s_xcachectrlBases[instance];
141         endLim  = s_xcachePhymemBases[instance] + s_xcachePhymemSizes[instance] - 0x01U;
142         endAddr = endAddr > endLim ? endLim : endAddr;
143 
144         /* Set the invalidate by line command and use the physical address. */
145         pccReg     = (base->CLCR & ~XCACHE_CLCR_LCMD_MASK) | XCACHE_CLCR_LCMD(1) | XCACHE_CLCR_LADSEL_MASK;
146         base->CLCR = pccReg;
147 
148         while (startAddr < endAddr)
149         {
150             /* Set the address and initiate the command. */
151             base->CSAR = (startAddr & XCACHE_CSAR_PHYADDR_MASK) | XCACHE_CSAR_LGO_MASK;
152 
153             /* Wait until the cache command completes. */
154             while ((base->CSAR & XCACHE_CSAR_LGO_MASK) != 0x00U)
155             {
156             }
157             startAddr += (uint32_t)XCACHE_LINESIZE_BYTE;
158         }
159     }
160 }
161 
162 /*!
163  * brief Cleans the cache.
164  *
165  */
XCACHE_CleanCache(XCACHE_Type * base)166 void XCACHE_CleanCache(XCACHE_Type *base)
167 {
168     /* Enable the to push all modified lines. */
169     base->CCR |= XCACHE_CCR_PUSHW0_MASK | XCACHE_CCR_PUSHW1_MASK | XCACHE_CCR_GO_MASK;
170 
171     /* Wait until the cache command completes. */
172     while ((base->CCR & XCACHE_CCR_GO_MASK) != 0x00U)
173     {
174     }
175 
176     /* As a precaution clear the bits to avoid inadvertently re-running this command. */
177     base->CCR &= ~(XCACHE_CCR_PUSHW0_MASK | XCACHE_CCR_PUSHW1_MASK);
178 }
179 
180 /*!
181  * brief Cleans cache by range.
182  *
183  * param address The physical address of cache.
184  * param size_byte size of the memory to be cleaned, should be larger than 0,
185  * better to align to size of cache line.
186  * note Address and size should be aligned to "XCACHE_LINESIZE_BYTE".
187  * The startAddr here will be forced to align to XCACHE_LINESIZE_BYTE if
188  * startAddr is not aligned. For the size_byte, application should make sure the
189  * alignment or make sure the right operation order if the size_byte is not aligned.
190  */
XCACHE_CleanCacheByRange(uint32_t address,uint32_t size_byte)191 void XCACHE_CleanCacheByRange(uint32_t address, uint32_t size_byte)
192 {
193     if (size_byte > 0UL)
194     {
195         uint32_t endAddr = address + size_byte - 0x01U;
196         uint32_t pccReg  = 0;
197         /* Align address to cache line size. */
198         uint32_t startAddr = address & ~((uint32_t)XCACHE_LINESIZE_BYTE - 1U);
199         uint32_t instance  = XCACHE_GetInstanceByAddr(address);
200         uint32_t endLim;
201         XCACHE_Type *base;
202 
203         if (instance >= ARRAY_SIZE(s_xcachectrlBases))
204         {
205             return;
206         }
207         base    = s_xcachectrlBases[instance];
208         endLim  = s_xcachePhymemBases[instance] + s_xcachePhymemSizes[instance] - 0x01U;
209         endAddr = endAddr > endLim ? endLim : endAddr;
210 
211         /* Set the push by line command. */
212         pccReg     = (base->CLCR & ~XCACHE_CLCR_LCMD_MASK) | XCACHE_CLCR_LCMD(2) | XCACHE_CLCR_LADSEL_MASK;
213         base->CLCR = pccReg;
214 
215         while (startAddr < endAddr)
216         {
217             /* Set the address and initiate the command. */
218             base->CSAR = (startAddr & XCACHE_CSAR_PHYADDR_MASK) | XCACHE_CSAR_LGO_MASK;
219 
220             /* Wait until the cache command completes. */
221             while ((base->CSAR & XCACHE_CSAR_LGO_MASK) != 0x00U)
222             {
223             }
224             startAddr += (uint32_t)XCACHE_LINESIZE_BYTE;
225         }
226     }
227 }
228 
229 /*!
230  * brief Cleans and invalidates the cache.
231  *
232  */
XCACHE_CleanInvalidateCache(XCACHE_Type * base)233 void XCACHE_CleanInvalidateCache(XCACHE_Type *base)
234 {
235     /* Push and invalidate all. */
236     base->CCR |= XCACHE_CCR_PUSHW0_MASK | XCACHE_CCR_PUSHW1_MASK | XCACHE_CCR_INVW0_MASK | XCACHE_CCR_INVW1_MASK |
237                  XCACHE_CCR_GO_MASK;
238 
239     /* Wait until the cache command completes. */
240     while ((base->CCR & XCACHE_CCR_GO_MASK) != 0x00U)
241     {
242     }
243 
244     /* As a precaution clear the bits to avoid inadvertently re-running this command. */
245     base->CCR &= ~(XCACHE_CCR_PUSHW0_MASK | XCACHE_CCR_PUSHW1_MASK | XCACHE_CCR_INVW0_MASK | XCACHE_CCR_INVW1_MASK);
246 }
247 
248 /*!
249  * brief Cleans and invalidate cache by range.
250  *
251  * param address The physical address of cache.
252  * param size_byte size of the memory to be Cleaned and Invalidated, should larger than 0,
253  * better to align to size of cache line.
254  * note Address and size should be aligned to "XCACHE_LINESIZE_BYTE".
255  * The startAddr here will be forced to align to XCACHE_LINESIZE_BYTE if
256  * startAddr is not aligned. For the size_byte, application should make sure the
257  * alignment or make sure the right operation order if the size_byte is not aligned.
258  */
XCACHE_CleanInvalidateCacheByRange(uint32_t address,uint32_t size_byte)259 void XCACHE_CleanInvalidateCacheByRange(uint32_t address, uint32_t size_byte)
260 {
261     if (size_byte > 0UL)
262     {
263         uint32_t endAddr = address + size_byte - 0x01U;
264         uint32_t pccReg  = 0;
265         /* Align address to cache line size. */
266         uint32_t startAddr = address & ~((uint32_t)XCACHE_LINESIZE_BYTE - 1U);
267         uint32_t instance  = XCACHE_GetInstanceByAddr(address);
268         uint32_t endLim;
269         XCACHE_Type *base;
270 
271         if (instance >= ARRAY_SIZE(s_xcachectrlBases))
272         {
273             return;
274         }
275         base    = s_xcachectrlBases[instance];
276         endLim  = s_xcachePhymemBases[instance] + s_xcachePhymemSizes[instance] - 0x01U;
277         endAddr = endAddr > endLim ? endLim : endAddr;
278 
279         /* Set the push by line command. */
280         pccReg     = (base->CLCR & ~XCACHE_CLCR_LCMD_MASK) | XCACHE_CLCR_LCMD(3) | XCACHE_CLCR_LADSEL_MASK;
281         base->CLCR = pccReg;
282 
283         while (startAddr < endAddr)
284         {
285             /* Set the address and initiate the command. */
286             base->CSAR = (startAddr & XCACHE_CSAR_PHYADDR_MASK) | XCACHE_CSAR_LGO_MASK;
287 
288             /* Wait until the cache command completes. */
289             while ((base->CSAR & XCACHE_CSAR_LGO_MASK) != 0x00U)
290             {
291             }
292             startAddr += (uint32_t)XCACHE_LINESIZE_BYTE;
293         }
294     }
295 }
296 
297 #if !((defined(FSL_FEATURE_XCACHE_HAS_NO_WRITE_BUF)) && (FSL_FEATURE_XCACHE_HAS_NO_WRITE_BUF))
298 /*!
299  * brief Enable the cache write buffer.
300  *
301  */
XCACHE_EnableWriteBuffer(XCACHE_Type * base,bool enable)302 void XCACHE_EnableWriteBuffer(XCACHE_Type *base, bool enable)
303 {
304     if (enable)
305     {
306         base->CCR |= XCACHE_CCR_ENWRBUF_MASK;
307     }
308     else
309     {
310         base->CCR &= ~XCACHE_CCR_ENWRBUF_MASK;
311     }
312 }
313 #endif
314 
315 #endif /* FSL_FEATURE_SOC_XCACHE_COUNT > 0 */
316