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