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