1 /*
2 * Copyright (C) 2017-2024 Alibaba Group Holding Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <soc.h>
20 #include <csi_core.h>
21 #include <drv/tick.h>
22 #include <drv/porting.h>
23 #include <drv/irq.h>
24 #include "riscv_csr.h"
25
26 #if (defined(CONFIG_KERNEL_RHINO) || defined(CONFIG_KERNEL_FREERTOS) || defined(CONFIG_KERNEL_RTTHREAD)) && defined(CONFIG_KERNEL_NONE)
27 #error "Please check the current system is baremetal or not!!!"
28 #endif
29
30 #if !defined(CONFIG_SMP) || (defined(CONFIG_SMP) && !CONFIG_SMP)
31 #if CONFIG_NR_CPUS > 1
32 #error "Please define CONFIG_NR_CPUS as 1 or do not need define."
33 #endif
34 #endif
35
36 #if !CONFIG_INTC_CLIC_PLIC && CONFIG_SUPPORT_IRQ_NESTED
37 #error "Please disable CONFIG_SUPPORT_IRQ_NESTED in package.yaml when use PLIC."
38 #endif
39
40 #if CONFIG_ECC_L2_ENABLE
41 static csi_dev_t ecc_l2_dev;
42 #endif
43
44 extern void section_data_copy(void);
45 extern void section_ram_code_copy(void);
46 extern void section_bss_clear(void);
47
48 #ifdef CONFIG_RISCV_SMODE
49 extern unsigned long __Vectors;
50 unsigned long page_table_l2[512] __attribute__ ((aligned(4096)));
51 unsigned long page_table_l1[512] __attribute__ ((aligned(4096)));
52 unsigned long page_table_l0[512] __attribute__ ((aligned(4096)));
53
54 void _mmu_init(void) __attribute__((noinline));
_mmu_init(void)55 void _mmu_init(void)
56 {
57 #if CONFIG_CPU_XUANTIE_C906 || CONFIG_CPU_XUANTIE_C906FD || CONFIG_CPU_XUANTIE_C906FDV \
58 || CONFIG_CPU_XUANTIE_C908 || CONFIG_CPU_XUANTIE_C908V || CONFIG_CPU_XUANTIE_C908I \
59 || CONFIG_CPU_XUANTIE_R910 || CONFIG_CPU_XUANTIE_R920
60 unsigned long status = __get_MXSTATUS();
61 /* open MAEE for thead-mmu extension */
62 status |= (1 << 21);
63 __set_MXSTATUS(status);
64
65 page_table_l2[0] = 0x1 | ((unsigned long)page_table_l1 >> 12) << 10;
66 page_table_l1[0] = 0x1 | ((unsigned long)page_table_l0 >> 12) << 10;
67 /* setup mmu VA(0M ~ 1M-1) <==> PA(0M ~ 1M-1) */
68 for (unsigned long i = 0; i < 256; i++) {
69 page_table_l0[i] = (UPPER_ATTRS(ATTR_CA | ATTR_SH) | i << 10 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
70 }
71
72 /* setup mmu VA(2M ~ 1G-1) <==> PA(2M ~ 1G-1) */
73 for (unsigned long i = 1; i < 512; i++) {
74 page_table_l1[i] = (UPPER_ATTRS(ATTR_SO | ATTR_SH) | i << 19 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
75 }
76
77 /* setup mmu VA(1G ~ 2G-1) <==> PA(1G ~ 2G-1) */
78 page_table_l2[1] = (UPPER_ATTRS(ATTR_CA | ATTR_SH) | (1) << 28 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
79 #elif CONFIG_CPU_XUANTIE_C907_RV32 || CONFIG_CPU_XUANTIE_C907FD_RV32 || CONFIG_CPU_XUANTIE_C907FDV_RV32 || CONFIG_CPU_XUANTIE_C907FDVM_RV32
80 unsigned long envcfgh = __get_MENVCFGH();
81 /* enable svpbmt */
82 envcfgh |= (1 << 30);
83 __set_MENVCFGH(envcfgh);
84
85 page_table_l1[0] = 0x1 | ((unsigned long)page_table_l0 >> 12) << 10;
86 /* setup mmu VA(0M ~ 1M-1) <==> PA(0M ~ 1M-1) */
87 for (unsigned long i = 0; i < 256; i++) {
88 page_table_l0[i] = (SVPBMT_PMA | (i) << 10 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
89 }
90
91 /* setup mmu VA(4M ~ 1G-1) <==> PA(4M ~ 1G-1) */
92 for (unsigned long i = 1; i < 256; i++) {
93 page_table_l1[i] = (SVPBMT_IO | (i) << 20 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
94 }
95
96 /* setup mmu VA(1G ~ 2G-1) <==> PA(1G ~ 2G-1) */
97 for (unsigned long i = 256; i < 512; i++) {
98 page_table_l1[i] = (SVPBMT_PMA | (i) << 20 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
99 }
100 #else
101 unsigned long envcfg = __get_MENVCFG();
102 /* enable svpbmt */
103 envcfg |= (1ull << 62);
104 __set_MENVCFG(envcfg);
105
106 page_table_l2[0] = 0x1 | ((unsigned long)page_table_l1 >> 12) << 10;
107 page_table_l1[0] = 0x1 | ((unsigned long)page_table_l0 >> 12) << 10;
108 /* setup mmu VA(0M ~ 1M-1) <==> PA(0M ~ 1M-1) */
109 for (unsigned long i = 0; i < 256; i++) {
110 page_table_l0[i] = (SVPBMT_PMA | (i) << 10 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
111 }
112
113 /* setup mmu VA(2M ~ 1G-1) <==> PA(2M ~ 1G-1) */
114 for (unsigned long i = 1; i < 512; i++) {
115 page_table_l1[i] = (SVPBMT_IO | (i) << 19 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
116 }
117
118 /* setup mmu VA(1G ~ 2G-1) <==> PA(1G ~ 2G-1) */
119 page_table_l2[1] = (SVPBMT_PMA | (1) << 28 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
120 #endif
121
122 #if __riscv_xlen == 64
123 csi_dcache_clean_range((unsigned long *)&page_table_l2, sizeof(page_table_l2));
124 #endif
125 csi_dcache_clean_range((unsigned long *)&page_table_l1, sizeof(page_table_l1));
126 csi_dcache_clean_range((unsigned long *)&page_table_l0, sizeof(page_table_l0));
127 csi_mmu_invalid_tlb_all();
128 #if __riscv_xlen == 64
129 __set_SATP(((unsigned long)&page_table_l2 >> 12));
130 csi_mmu_set_mode(MMU_MODE_39);
131 csi_mmu_enable();
132 #else
133 __set_SATP(((unsigned long)&page_table_l1 >> 12));
134 csi_mmu_set_mode(MMU_MODE_32);
135 csi_mmu_enable();
136 #endif
137 }
138
_system_switchto_smode(void)139 void _system_switchto_smode(void)
140 {
141 unsigned long m_status = __get_MSTATUS();
142 m_status &= ~MSTATUS_TVM_MASK;
143 m_status &= ~MSTATUS_MPP_MASK;
144 m_status |= MSTATUS_MPP_S;
145 __set_MSTATUS(m_status);
146
147 /* setup S-Mode csr regs */
148 __set_STVEC((unsigned long)(&__Vectors) | 0x1);
149 //FIXME:
150 __ASM("auipc a0, 0");
151 __ASM("addi a0, a0, 14");
152 __ASM("csrw mepc, a0");
153 __ASM("mret");
154 }
155
_system_init_for_smode(void)156 void _system_init_for_smode(void)
157 {
158 _system_switchto_smode();
159 }
160
smode_init(void)161 void smode_init(void)
162 {
163 /* may be not clear after reset on FPGA */
164 csi_mmu_disable();
165 _mmu_init();
166 _system_init_for_smode();
167 }
168 #endif
169
170 /**
171 * @brief initialize pmp
172 * @param None
173 * @return None
174 */
pmp_init(void)175 static void pmp_init(void)
176 {
177 long addr;
178
179 addr = 0x90000000UL >> 2;
180 __set_PMPADDR0(addr);
181 __set_PMPxCFG(0, 0x8f);
182 }
183
fpp_init(void)184 static void fpp_init(void)
185 {
186 #if CONFIG_FPP_ENABLE
187 csi_fpp_set_base_addr(0x19000000);
188 csi_fpp_enable();
189 #endif
190 }
191
192 #if CONFIG_INTC_CLIC_PLIC
clic_init(void)193 static void clic_init(void)
194 {
195 int i;
196
197 /* get interrupt level from info */
198 CLIC->CLICCFG = (((CLIC->CLICINFO & CLIC_INFO_CLICINTCTLBITS_Msk) >> CLIC_INFO_CLICINTCTLBITS_Pos) << CLIC_CLICCFG_NLBIT_Pos);
199
200 for (i = 0; i < 64; i++) {
201 uint8_t nlbits = (CLIC->CLICINFO & CLIC_INFO_CLICINTCTLBITS_Msk) >> CLIC_INFO_CLICINTCTLBITS_Pos;
202 CLIC->CLICINT[i].CTL = (CLIC->CLICINT[i].CTL & (~CLIC_INTCFG_PRIO_Msk)) | (0x1 << (8 - nlbits));
203 CLIC->CLICINT[i].IP = 0;
204 CLIC->CLICINT[i].ATTR = 1; /* use vector interrupt */
205 }
206
207 /* tspend use positive interrupt */
208 CLIC->CLICINT[Machine_Software_IRQn].ATTR = 0x3;
209 csi_irq_enable(Machine_Software_IRQn);
210
211 /* enable external plic interrupt */
212 csi_irq_enable(Machine_External_IRQn);
213
214 #if CONFIG_ECC_L1_ENABLE || CONFIG_ECC_ITCM_ENABLE || CONFIG_ECC_DTCM_ENABLE
215 CLIC->CLICINT[L1_CACHE_ECC_IRQn].ATTR = 0x3;
216 csi_irq_enable(L1_CACHE_ECC_IRQn);
217 #endif
218 }
219 #endif
220
interrupt_init(void)221 static void interrupt_init(void)
222 {
223 int i;
224
225 #if CONFIG_INTC_CLIC_PLIC
226 clic_init();
227 for (i = 0; i < CONFIG_IRQ_NUM - PLIC_IRQ_OFFSET; i++) {
228 PLIC->PLIC_PRIO[i] = 31;
229 }
230
231 for (i = 0; i < (CONFIG_IRQ_NUM - PLIC_IRQ_OFFSET + 32) / 32; i++) {
232 PLIC->PLIC_IP[i] = 0;
233 }
234
235 for (i = 0; i < (CONFIG_IRQ_NUM - PLIC_IRQ_OFFSET + 32) / 32; i++) {
236 PLIC->PLIC_H0_MIE[i] = 0;
237 PLIC->PLIC_H0_SIE[i] = 0;
238 }
239
240 /* set hart threshold 0, enable all interrupt */
241 PLIC->PLIC_H0_MTH = 0;
242 PLIC->PLIC_H0_STH = 0;
243
244 for (i = 0; i < CONFIG_IRQ_NUM - PLIC_IRQ_OFFSET; i++) {
245 PLIC->PLIC_H0_MCLAIM = i;
246 PLIC->PLIC_H0_SCLAIM = i;
247 }
248
249 /* set PLIC_PER */
250 PLIC->PLIC_PER = 0x1;
251 #else
252 for (i = 0; i < CONFIG_IRQ_NUM; i++) {
253 PLIC->PLIC_PRIO[i] = 31;
254 }
255
256 for (i = 0; i < (CONFIG_IRQ_NUM + 32) / 32; i++) {
257 PLIC->PLIC_IP[i] = 0;
258 }
259
260 for (i = 0; i < (CONFIG_IRQ_NUM + 32) / 32; i++) {
261 PLIC->PLIC_H0_MIE[i] = 0;
262 PLIC->PLIC_H0_SIE[i] = 0;
263 }
264
265 /* set hart threshold 0, enable all interrupt */
266 PLIC->PLIC_H0_MTH = 0;
267 PLIC->PLIC_H0_STH = 0;
268
269 for (i = 0; i < CONFIG_IRQ_NUM; i++) {
270 PLIC->PLIC_H0_MCLAIM = i;
271 PLIC->PLIC_H0_SCLAIM = i;
272 }
273
274 /* set PLIC_PER */
275 PLIC->PLIC_PER = 0x1;
276
277 /* enable MEIE & MTIE & MSIE */
278 uint32_t mie = __get_MIE();
279 mie |= (1 << 11 | 1 << 7 | 1 << 3);
280 #if CONFIG_ECC_L1_ENABLE || CONFIG_ECC_ITCM_ENABLE || CONFIG_ECC_DTCM_ENABLE
281 mie |= (1 << 16);
282 #endif
283 __set_MIE(mie);
284 #endif
285 }
286
section_init(void)287 static void section_init(void)
288 {
289 #if CONFIG_XIP
290 section_data_copy();
291 section_ram_code_copy();
292 csi_dcache_clean();
293 csi_icache_invalid();
294 #endif
295
296 section_bss_clear();
297 }
298
cache_init(void)299 static void cache_init(void)
300 {
301 /* enable cache */
302 csi_dcache_enable();
303 csi_icache_enable();
304 }
305
306 /**
307 * @brief initialize the system
308 * Initialize the psr and vbr.
309 * @param None
310 * @return None
311 */
SystemInit(void)312 void SystemInit(void)
313 {
314 #if CONFIG_CPU_XUANTIE_R908_CP || CONFIG_CPU_XUANTIE_R908FD_CP || CONFIG_CPU_XUANTIE_R908FDV_CP
315 /* enable theadisaee & MM */
316 unsigned long status = __get_MXSTATUS();
317 status &= ~(1 << 22);
318 status |= (1 << 24 | 1 << 15);
319 __set_MXSTATUS(status);
320 #else
321 /* enable theadisaee & MM */
322 unsigned long status = __get_MXSTATUS();
323 status |= (1 << 22 | 1 << 15);
324 __set_MXSTATUS(status);
325 #endif
326
327 #if __riscv_flen == 64
328 /* enable float ISA */
329 status = __get_MSTATUS();
330 status |= (1 << MSTATUS_FS_SHIFT);
331 __set_MSTATUS(status);
332 #endif
333 #ifdef __riscv_vector
334 /* enable vector ISA */
335 status = __get_MSTATUS();
336 status |= (1 << MSTATUS_VS_SHIFT);
337 __set_MSTATUS(status);
338 #endif
339
340 #if CONFIG_ECC_L1_ENABLE
341 /* enable L1 cache ecc */
342 uint64_t mhint = __get_MHINT();
343 mhint |= (0x1 << 19);
344 __set_MHINT(mhint);
345 #endif
346
347 #if CONFIG_ECC_L2_ENABLE
348 /* enable L2 cache ecc */
349 uint64_t mccr2 = __get_MCCR2();
350 mccr2 |= (0x1 << 1);
351 __set_MCCR2(mccr2);
352 #endif
353
354 #if CONFIG_ECC_ITCM_ENABLE
355 uint64_t mitcmcr = __get_MITCMCR();
356 mitcmcr |= MITCMCR_ECC_EN_Msk;
357 __set_MITCMCR(mitcmcr);
358 #endif
359
360 #if CONFIG_ECC_DTCM_ENABLE
361 uint64_t mdtcmcr = __get_MDTCMCR();
362 mdtcmcr |= MDTCMCR_ECC_EN_Msk;
363 __set_MDTCMCR(mdtcmcr);
364 #endif
365
366 #ifdef CONFIG_RISCV_SMODE
367 /* enable ecall delegate */
368 unsigned long medeleg = __get_MEDELEG();
369 medeleg |= (1 << 9);
370 __set_MEDELEG(medeleg);
371
372 /* enable interrupt delegate */
373 unsigned long mideleg = __get_MIDELEG();
374 mideleg |= 0x222;
375 __set_MIDELEG(mideleg);
376 #endif
377
378 #ifdef CONFIG_RISCV_SMODE
379 /* enable mcounteren for s-mode */
380 __set_MCOUNTEREN(0xffffffff);
381
382 #if CBO_INSN_SUPPORT
383 unsigned long envcfg = __get_MENVCFG();
384 /* enable CBIE & CBCFE & CBZE on lower priviledge */
385 envcfg |= (3 << 4 | 1 << 6 | 1 << 7);
386 __set_MENVCFG(envcfg);
387 #endif
388 #endif
389
390 cache_init();
391 section_init();
392 pmp_init();
393 fpp_init();
394
395 interrupt_init();
396 soc_set_sys_freq(20000000);
397 csi_tick_init();
398
399 #if CONFIG_ECC_L2_ENABLE
400 extern void ecc_l2_irqhandler(void *arg);
401 /* l2 cache ecc interrupt register */
402 ecc_l2_dev.irq_num = L2_CACHE_ECC_IRQn;
403 csi_irq_attach(ecc_l2_dev.irq_num, ecc_l2_irqhandler, &ecc_l2_dev);
404 csi_irq_enable(ecc_l2_dev.irq_num);
405 #endif
406 }
407