1 /*
2 // Copyright (C) 2022 Beken Corporation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include "platform.h"
18 #include <os/os.h>
19 #include <components/system.h>
20 #include "cache.h"
21
22 /* CSR NDS_ICM_CFG */
23 #define ISET_MSK ((1ULL << 2) | (1ULL << 1) | (1ULL << 0))
24 #define IWAY_MSK ((1ULL << 5) | (1ULL << 4) | (1ULL << 3))
25 #define ISIZE_MSK ((1ULL << 8) | (1ULL << 7) | (1ULL << 6))
26
27 /* CSR NDS_DCM_CFG */
28 #define DSET_MSK ((1ULL << 2) | (1ULL << 1) | (1ULL << 0))
29 #define DWAY_MSK ((1ULL << 5) | (1ULL << 4) | (1ULL << 3))
30 #define DSIZE_MSK ((1ULL << 8) | (1ULL << 7) | (1ULL << 6))
31
32 /* CSR NDS_MCACHE_CTL */
33 #define DC_WARND_MSK (3UL << 13)
34 #define CCTL_SUEN_MSK (1ULL << 8)
35
36 /* CSR NDS_MMSC_CFG */
37 #define CCTLCSR_MSK (1ULL << 16)
38 #define VCCTL_MSK ((1ULL << 18) | (1ULL << 19))
39
40 /* AndeStar CCTL Command Machine mode */
41 /* Allow S/U mode */
42 #define CCTL_L1D_VA_INVAL 0
43 /* Allow S/U mode */
44 #define CCTL_L1D_VA_WB 1
45 /* Allow S/U mode */
46 #define CCTL_L1D_VA_WBINVAL 2
47 #define CCTL_L1D_VA_LOCK 3
48 #define CCTL_L1D_VA_UNLOCK 4
49 #define CCTL_L1D_WBINVAL_ALL 6
50 #define CCTL_L1D_WB_ALL 7
51 /* Allow S/U mode */
52 #define CCTL_L1I_VA_INVAL 8
53 #define CCTL_L1I_VA_LOCK 11
54 #define CCTL_L1I_VA_UNLOCK 12
55 #define CCTL_L1D_IX_INVAL 16
56 #define CCTL_L1D_IX_WB 17
57 #define CCTL_L1D_IX_WBINVAL 18
58 #define CCTL_L1D_IX_RTAG 19
59 #define CCTL_L1D_IX_RDATA 20
60 #define CCTL_L1D_IX_WTAG 21
61 #define CCTL_L1D_IX_WDATA 22
62 #define CCTL_L1D_INVAL_ALL 23
63 #define CCTL_L1I_IX_INVAL 24
64 #define CCTL_L1I_IX_RTAG 27
65 #define CCTL_L1I_IX_RDATA 28
66 #define CCTL_L1I_IX_WTAG 29
67 #define CCTL_L1I_IX_WDATA 30
68
69 #define USE_CCTL 0
70 #define BUF_SIZE 0x100
71
72 /* SMU.SYSTEMCFG Configuration Register */
73 #define L2C_CTL_OFF 8
74 #define L2C_CTL_MSK (0x1 << L2C_CTL_OFF)
75
76 /* Configuration Register */
77 #define L2C_SIZE_OFF 7
78 #define L2C_SIZE_MSK (0x1F << L2C_SIZE_OFF)
79 #define L2C_SIZE_0KB (0x00 << L2C_SIZE_OFF)
80 #define L2C_SIZE_128KB (0x01 << L2C_SIZE_OFF)
81 #define L2C_SIZE_256KB (0x02 << L2C_SIZE_OFF)
82 #define L2C_SIZE_512KB (0x04 << L2C_SIZE_OFF)
83 #define L2C_SIZE_1024KB (0x08 << L2C_SIZE_OFF)
84 #define L2C_SIZE_2048KB (0x10 << L2C_SIZE_OFF)
85 #define L2C_LINE_SIZE 32
86
87 /* Control Register */
88 #define L2C_ENABLE 0x1
89
90 /* Prefetch Threshold */
91 #define PFTHRES_OFF 1
92 #define PFTHRES_MSK (0x3 << PFTHRES_OFF)
93
94 /* Instruction Prefetch Depth */
95 #define IPFDPT_OFF 3
96 #define IPFDPT_MSK (0x3 << IPFDPT_OFF)
97 #define IPFDPT_3REQ (0x3 << IPFDPT_OFF)
98
99 /* Data Prefetch Depth */
100 #define DPFDPT_OFF 5
101 #define DPFDPT_MSK (0x3 << DPFDPT_OFF)
102 #define DPFDPT_3REQ (0x3 << DPFDPT_OFF)
103
104 /* Tag Ram output cycle */
105 #define TRAMOCTL_OFF 8
106 #define TRAMOCTL_MSK (0x3 << TRAMOCTL_OFF)
107
108 /* Tag Ram setup cycle */
109 #define TRAMICTL_OFF 10
110 #define TRAMICTL_MSK (0x1 << TRAMICTL_OFF)
111
112 /* Data Ram output cycle */
113 #define DRAMOCTL_OFF 11
114 #define DRAMOCTL_MSK (0x3 << DRAMOCTL_OFF)
115
116 /* Data Ram setup cycle */
117 #define DRAMICTL_OFF 13
118 #define DRAMICTL_MSK (0x1 << DRAMICTL_OFF)
119
120 /* CCTL Command Register */
121 #define CCTL_L2_IX_INVAL 0x0
122 #define CCTL_L2_IX_WB 0x1
123 #define CCTL_L2_IX_WBINVAL 0x2
124 #define CCTL_L2_PA_INVAL 0x8
125 #define CCTL_L2_PA_WB 0x9
126 #define CCTL_L2_PA_WBINVAL 0xA
127 #define CCTL_L2_TGT_WRITE 0x10
128 #define CCTL_L2_TGT_READ 0x11
129 #define CCTL_L2_WBINVAL_ALL 0x12
130
131 /* CCTL Access Line Registers */
132 #define CCTL_L2_ACC_SET_OFF 5
133 #define CCTL_L2_ACC_SET_MSK (0x7FFF << CCTL_L2_ACC_SET_OFF)
134 #define CCTL_L2_ACC_WAY_OFF 28
135 #define CCTL_L2_ACC_WAY_MSK (0xF << CCTL_L2_ACC_WAY_OFF)
136 #define CCTL_L2_ACC_RAMID_OFF 26
137 #define CCTL_L2_ACC_RAMID_MSK (0x3 << CCTL_L2_ACC_RAMID_OFF)
138
139 /* CCTL Status Register */
140 #define CCTL_L2_ST_IDLE 0
141 #define CCTL_L2_ST_RUNNING 1
142 #define CCTL_L2_ST_INVALID 2
143 #define CCTL_ST_MASK 0xF
144
145 #define SRAM_CACHE_CONFIG_BASE 0x3fff0048
146
147 #if !CONFIG_CACHE_CUSTOM_SRAM_MAPPING
148 #if !CONFIG_CACHE_ENABLE
149 const unsigned int g_sram_addr_map[SRAM_BLOCK_COUNT] = {
150 0x30020000,
151 0x30040000,
152 0x30060000,
153 0x30000000
154 };
155 #else //#if CONFIG_CACHE_ENABLE
156 const unsigned int g_sram_addr_map[SRAM_BLOCK_COUNT] = {
157 0x38000000,
158 0x38020000,
159 0x30000000,
160 0x30020000
161 };
162 #endif //#if CONFIG_CACHE_ENABLE
163 #else //#if !CONFIG_CACHE_CUSTOM_SRAM_MAPPING
164 extern unsigned int g_sram_addr_map[SRAM_BLOCK_COUNT];
165 #endif //#if !CONFIG_CACHE_CUSTOM_SRAM_MAPPING
166
sram_dcache_map(void)167 void sram_dcache_map(void)
168 {
169 int i = 0;
170 unsigned int addr, data;
171
172 for(i = 0; i < SRAM_BLOCK_COUNT; i++)
173 {
174 addr = SRAM_CACHE_CONFIG_BASE + (i * SRAM_BLOCK_COUNT);
175 data = *((volatile unsigned int *) (addr));
176 *((volatile unsigned int *) (addr)) = (g_sram_addr_map[i]) + (data & 0x03ff);
177 }
178 }
179
show_cache_config_info(void)180 int show_cache_config_info(void)
181 {
182 unsigned int iset, iway, isize, dset, dway, dsize;
183 unsigned long icm_cfg = 0, dcm_cfg = 0;
184
185 /* Check if support CCTL feature */
186 if (read_csr(NDS_MMSC_CFG) & CCTLCSR_MSK) {
187 os_printf("CPU supports CCTL operation\n");
188
189 if (read_csr(NDS_MMSC_CFG) & VCCTL_MSK) {
190 os_printf("CPU supports CCTL auto-increment\n");
191 } else {
192 os_printf("CPU does NOT support CCTL auto-increment\n");
193 }
194
195 } else {
196 os_printf("CPU supports FENCE operation\n");
197 }
198
199 /* Enable I/D cache HW prefetcher and D-cache write-around (threshold: 4 cache lines) as default */
200 // clear_csr(NDS_MCACHE_CTL, DC_WARND_MSK);
201 // set_csr(NDS_MCACHE_CTL, (1 << 13) | (1 << 10) | (1 << 9));
202
203 /* Get ICache ways, sets, line size */
204 icm_cfg = read_csr(NDS_MICM_CFG);
205 if ((icm_cfg & ISET_MSK) < 7) {
206 iset = (unsigned int)(1 << ((icm_cfg & ISET_MSK) + 6));
207 } else {
208 iset = 0;
209 }
210 os_printf("The L1C ICache sets = %u\n", iset);
211
212 iway = (unsigned int)(((icm_cfg & IWAY_MSK) >> 3) + 1);
213 os_printf("The L1C ICache ways = %u\n", iway);
214
215 if (((icm_cfg & ISIZE_MSK) >> 6) && (((icm_cfg & ISIZE_MSK) >> 6) <= 5)) {
216 isize = (unsigned int)(1 << (((icm_cfg & ISIZE_MSK) >> 6) + 2));
217 } else if (((icm_cfg & ISIZE_MSK) >> 6) >= 6) {
218 os_printf("Warning L1C i cacheline size is reserved value\n");
219 isize = 0;
220 } else {
221 isize = 0;
222 }
223
224 os_printf("The L1C ICache line size = %u\n", isize);
225 if (isize == 0) {
226 os_printf("This CPU doesn't have L1C ICache.\n");
227 return 0;
228 } else {
229 /* Enable L1C ICache */
230 // set_csr(NDS_MCACHE_CTL, (0x1 << 0));
231 }
232
233 /* Get DCache ways, sets, line size */
234 dcm_cfg = read_csr(NDS_MDCM_CFG);
235 if ((dcm_cfg & DSET_MSK) < 7) {
236 dset = (unsigned int)(1 << ((dcm_cfg & DSET_MSK) + 6));
237 } else {
238 dset = 0;
239 }
240 os_printf("The L1C DCache sets = %u\n", dset);
241
242 dway = (unsigned int)(((dcm_cfg & DWAY_MSK) >> 3) + 1);
243 os_printf("The L1C DCache ways = %u\n", dway);
244
245 if (((dcm_cfg & DSIZE_MSK) >> 6) && (((dcm_cfg & DSIZE_MSK) >> 6) <= 5)) {
246 dsize = (unsigned int)(1 << (((dcm_cfg & DSIZE_MSK) >> 6) + 2));
247 } else if (((dcm_cfg & DSIZE_MSK) >> 6) >= 6) {
248 os_printf("Warning L1C d cacheline size is reserved value\n");
249 dsize = 0;
250 } else {
251 dsize = 0;
252 }
253
254 os_printf("The L1C DCache line size = %u\n", dsize);
255 if (dsize == 0) {
256 os_printf("This CPU doesn't have L1C DCache.\n");
257 return 0;
258 } else {
259 /* Enable L1C DCache */
260 // set_csr(NDS_MCACHE_CTL, (0x1 << 1));
261 }
262
263 if (read_csr(NDS_MCACHE_CTL) & 0x1) {
264 os_printf("Enable L1C I cache\n");
265 }
266
267 if (read_csr(NDS_MCACHE_CTL) & 0x2) {
268 os_printf("Enable L1C D cache\n");
269 }
270
271 if (!(read_csr(NDS_MCACHE_CTL) & 0x3)) {
272 os_printf("Can't enable L1C I/D cache\n");
273 }
274
275 return 1;
276 }
277
flush_dcache(void * va,long size)278 void flush_dcache(void *va, long size)
279 {
280 // os_printf("I/D cache flush\n");
281
282 if(read_csr(NDS_MMSC_CFG) & CCTLCSR_MSK) {
283 unsigned int i, tmp = 0, dsize = 0;
284
285 dsize = (unsigned int)(1 << (((read_csr(NDS_MDCM_CFG) & DSIZE_MSK) >> 6) + 2));
286
287 /* Check whether the CPU configured with CCTL auto-incremented feature. */
288 if ((read_csr(NDS_MMSC_CFG) & VCCTL_MSK)) {
289 unsigned long final_va = (unsigned long)(va + size);
290 unsigned long next_va = (unsigned long)va;
291
292 /* Write only once at the beginning, it will be updated by CCTL command CSR write operation */
293 write_csr(NDS_MCCTLBEGINADDR, (unsigned long)va);
294
295 /* L1C DCache write back and invalidate */
296 while (next_va < final_va) {
297 /* Write back and invalid one cache line each time */
298 write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_VA_WBINVAL);
299
300 /* Read back from BEGINADDR csr for next va */
301 next_va = read_csr(NDS_MCCTLBEGINADDR);
302 }
303
304 } else {
305 /* L1C DCache write back and invalidate */
306 for (i = 0; tmp < size; i++) {
307 /* Write back and invalid one cache line each time */
308 write_csr(NDS_MCCTLBEGINADDR, (unsigned long)(va + (i * dsize)));
309 tmp += dsize;
310 write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_VA_WBINVAL);
311 }
312 }
313
314 } else {
315 /* FENCE.I go data writeback w/o data invalid but instruction invalid.
316 As src code is copied to dst and go to execute dst instruction,
317 you should use FENCE.I instead of FENCE */
318 __nds__fencei();
319 }
320 }
321
flush_all_dcache(void)322 void flush_all_dcache(void) {
323 int i = 0;
324 for(i = 0; i < SRAM_BLOCK_COUNT; i++)
325 {
326 if(g_sram_addr_map[i] & 0x08000000) {
327 flush_dcache((void *)g_sram_addr_map[i], SRAM_BLOCK_SIZE);
328 }
329 }
330 }