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_ECC_L2_ENABLE
37 static csi_dev_t ecc_l2_dev;
38 #endif
39 
40 extern void section_data_copy(void);
41 extern void section_ram_code_copy(void);
42 extern void section_bss_clear(void);
43 
44 #ifdef CONFIG_RISCV_SMODE
45 extern unsigned long __Vectors;
46 unsigned long page_table_l2[512] __attribute__ ((aligned(4096)));
47 unsigned long page_table_l1[512] __attribute__ ((aligned(4096)));
48 unsigned long page_table_l0[512] __attribute__ ((aligned(4096)));
49 
50 void _mmu_init(void) __attribute__((noinline));
_mmu_init(void)51 void _mmu_init(void)
52 {
53 #if CONFIG_CPU_XUANTIE_C906 || CONFIG_CPU_XUANTIE_C906FD || CONFIG_CPU_XUANTIE_C906FDV \
54     || CONFIG_CPU_XUANTIE_C908 || CONFIG_CPU_XUANTIE_C908V || CONFIG_CPU_XUANTIE_C908I \
55     || CONFIG_CPU_XUANTIE_R910 || CONFIG_CPU_XUANTIE_R920
56     unsigned long status = __get_MXSTATUS();
57     /* open MAEE for thead-mmu extension */
58     status |= (1 << 21);
59     __set_MXSTATUS(status);
60 
61     page_table_l2[0] = 0x1 | ((unsigned long)page_table_l1 >> 12) << 10;
62     page_table_l1[0] = 0x1 | ((unsigned long)page_table_l0 >> 12) << 10;
63     /* setup mmu VA(0M ~ 1M-1) <==>  PA(0M ~ 1M-1) */
64     for (unsigned long i = 0; i < 256; i++) {
65         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;
66     }
67 
68     /* setup mmu VA(2M ~ 1G-1) <==>  PA(2M ~ 1G-1) */
69     for (unsigned long i = 1; i < 512; i++) {
70         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;
71     }
72 
73     /* setup mmu VA(1G ~ 2G-1) <==>  PA(1G ~ 2G-1) */
74     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;
75 #elif CONFIG_CPU_XUANTIE_C907_RV32 || CONFIG_CPU_XUANTIE_C907FD_RV32 || CONFIG_CPU_XUANTIE_C907FDV_RV32 || CONFIG_CPU_XUANTIE_C907FDVM_RV32
76     unsigned long envcfgh = __get_MENVCFGH();
77     /* enable svpbmt */
78     envcfgh |= (1 << 30);
79     __set_MENVCFGH(envcfgh);
80 
81     page_table_l1[0] = 0x1 | ((unsigned long)page_table_l0 >> 12) << 10;
82     /* setup mmu VA(0M ~ 1M-1) <==>  PA(0M ~ 1M-1) */
83     for (unsigned long i = 0; i < 256; i++) {
84         page_table_l0[i] = (SVPBMT_PMA | (i) << 10 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
85     }
86 
87     /* setup mmu VA(4M ~ 1G-1) <==>  PA(4M ~ 1G-1) */
88     for (unsigned long i = 1; i < 256; i++) {
89         page_table_l1[i] = (SVPBMT_IO | (i) << 20 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
90     }
91 
92     /* setup mmu VA(1G ~ 2G-1) <==>  PA(1G ~ 2G-1) */
93     for (unsigned long i = 256; i < 512; i++) {
94         page_table_l1[i] = (SVPBMT_PMA | (i) << 20 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
95     }
96 #else
97     unsigned long envcfg = __get_MENVCFG();
98     /* enable svpbmt */
99     envcfg |= (1ull << 62);
100     __set_MENVCFG(envcfg);
101 
102     page_table_l2[0] = 0x1 | ((unsigned long)page_table_l1 >> 12) << 10;
103     page_table_l1[0] = 0x1 | ((unsigned long)page_table_l0 >> 12) << 10;
104     /* setup mmu VA(0M ~ 1M-1) <==>  PA(0M ~ 1M-1) */
105     for (unsigned long i = 0; i < 256; i++) {
106         page_table_l0[i] = (SVPBMT_PMA | (i) << 10 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
107     }
108 
109     /* setup mmu VA(2M ~ 1G-1) <==>  PA(2M ~ 1G-1) */
110     for (unsigned long i = 1; i < 512; i++) {
111         page_table_l1[i] = (SVPBMT_IO | (i) << 19 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
112     }
113 
114     /* setup mmu VA(1G ~ 2G-1) <==>  PA(1G ~ 2G-1) */
115     page_table_l2[1] = (SVPBMT_PMA | (1) << 28 | LOWER_ATTRS(DIRTY_FLAG | ACCESS_FLAG | AP_X | AP_W | AP_R | GLOBAL_FLAG)) | 0x1;
116 #endif
117 
118 #if __riscv_xlen == 64
119     csi_dcache_clean_range((unsigned long *)&page_table_l2, sizeof(page_table_l2));
120 #endif
121     csi_dcache_clean_range((unsigned long *)&page_table_l1, sizeof(page_table_l1));
122     csi_dcache_clean_range((unsigned long *)&page_table_l0, sizeof(page_table_l0));
123     csi_mmu_invalid_tlb_all();
124 #if __riscv_xlen == 64
125     __set_SATP(((unsigned long)&page_table_l2 >> 12));
126     csi_mmu_set_mode(MMU_MODE_39);
127     csi_mmu_enable();
128 #else
129     __set_SATP(((unsigned long)&page_table_l1 >> 12));
130     csi_mmu_set_mode(MMU_MODE_32);
131     csi_mmu_enable();
132 #endif
133 }
134 
_system_switchto_smode(void)135 void _system_switchto_smode(void)
136 {
137     unsigned long m_status = __get_MSTATUS();
138     m_status &= ~MSTATUS_TVM_MASK;
139     m_status &= ~MSTATUS_MPP_MASK;
140     m_status |= MSTATUS_MPP_S;
141     __set_MSTATUS(m_status);
142 
143     /* setup S-Mode csr regs */
144     __set_STVEC((unsigned long)(&__Vectors) | 0x1);
145     //FIXME:
146     __ASM("auipc a0, 0");
147     __ASM("addi  a0, a0, 14");
148     __ASM("csrw  mepc, a0");
149     __ASM("mret");
150 }
151 
_system_init_for_smode(void)152 void _system_init_for_smode(void)
153 {
154     _system_switchto_smode();
155 }
156 
smode_init(void)157 void smode_init(void)
158 {
159     /* may be not clear after reset on FPGA */
160     csi_mmu_disable();
161     _mmu_init();
162     _system_init_for_smode();
163 }
164 #endif
165 
166 /**
167   * @brief  initialize pmp
168   * @param  None
169   * @return None
170   */
pmp_init(void)171 static void pmp_init(void)
172 {
173     long addr;
174 
175     addr = 0x90000000UL >> 2;
176     __set_PMPADDR0(addr);
177     __set_PMPxCFG(0, 0x8f);
178 }
179 
interrupt_init(void)180 static void interrupt_init(void)
181 {
182     int i;
183 
184     for (i = 0; i < CONFIG_IRQ_NUM; i++) {
185         PLIC->PLIC_PRIO[i] = 31;
186     }
187 
188     for (i = 0; i < (CONFIG_IRQ_NUM + 32) / 32; i++) {
189         PLIC->PLIC_IP[i] = 0;
190     }
191 
192     for (i = 0; i < (CONFIG_IRQ_NUM + 32) / 32; i++) {
193         PLIC->PLIC_H0_MIE[i] = 0;
194         PLIC->PLIC_H0_SIE[i] = 0;
195     }
196 
197     /* set hart threshold 0, enable all interrupt */
198     PLIC->PLIC_H0_MTH = 0;
199     PLIC->PLIC_H0_STH = 0;
200 
201     for (i = 0; i < CONFIG_IRQ_NUM; i++) {
202         PLIC->PLIC_H0_MCLAIM = i;
203         PLIC->PLIC_H0_SCLAIM = i;
204     }
205 
206     /* set PLIC_PER */
207     PLIC->PLIC_PER = 0x1;
208 
209     /* enable MEIE & MTIE & MSIE */
210     uint32_t mie = __get_MIE();
211     mie |= (1 << 11 | 1 << 7 | 1 << 3);
212 #if CONFIG_ECC_L1_ENABLE
213     mie |= (1 << 16);
214 #endif
215     __set_MIE(mie);
216 }
217 
section_init(void)218 static void section_init(void)
219 {
220 #if CONFIG_XIP
221     section_data_copy();
222     section_ram_code_copy();
223     csi_dcache_clean();
224     csi_icache_invalid();
225 #endif
226 
227     section_bss_clear();
228 }
229 
cache_init(void)230 static void cache_init(void)
231 {
232     /* enable cache */
233     csi_dcache_enable();
234     csi_icache_enable();
235 }
236 
237 /**
238   * @brief  initialize the system
239   *         Initialize the psr and vbr.
240   * @param  None
241   * @return None
242   */
SystemInit(void)243 void SystemInit(void)
244 {
245 #if CONFIG_CPU_XUANTIE_C910V3_CP || CONFIG_CPU_XUANTIE_C920V3_CP
246     /* disable theadisaee & enable MM */
247     unsigned long status = __get_MXSTATUS();
248     status &= ~(1 << 22);
249     status |= (1 << 24 | 1 << 15);
250     __set_MXSTATUS(status);
251 #else
252     /* enable theadisaee & MM */
253     unsigned long status = __get_MXSTATUS();
254     status |= (1 << 22 | 1 << 15);
255     __set_MXSTATUS(status);
256 #endif
257 
258 #if __riscv_flen == 64
259     /* enable float ISA */
260     status = __get_MSTATUS();
261     status |= (1 << MSTATUS_FS_SHIFT);
262     __set_MSTATUS(status);
263 #endif
264 #ifdef __riscv_vector
265     /* enable vector ISA */
266     status = __get_MSTATUS();
267     status |= (1 << MSTATUS_VS_SHIFT);
268     __set_MSTATUS(status);
269 #endif
270 
271 #if CONFIG_ECC_L1_ENABLE
272     /* enable L1 cache ecc */
273     uint64_t mhint = __get_MHINT();
274     mhint |= (0x1 << 19);
275     __set_MHINT(mhint);
276 #endif
277 
278 #if CONFIG_ECC_L2_ENABLE
279     /* enable L2 cache ecc */
280     uint64_t mccr2 = __get_MCCR2();
281     mccr2 |= (0x1 << 1);
282     __set_MCCR2(mccr2);
283 #endif
284 
285 #ifdef CONFIG_RISCV_SMODE
286     /* enable ecall delegate */
287     unsigned long medeleg = __get_MEDELEG();
288     medeleg |= (1 << 9);
289     __set_MEDELEG(medeleg);
290 
291     /* enable interrupt delegate */
292     unsigned long mideleg = __get_MIDELEG();
293     mideleg |= 0x222;
294     __set_MIDELEG(mideleg);
295 #endif
296 
297 #ifdef CONFIG_RISCV_SMODE
298     /* enable mcounteren for s-mode */
299     __set_MCOUNTEREN(0xffffffff);
300 
301 #if CBO_INSN_SUPPORT
302     unsigned long envcfg = __get_MENVCFG();
303     /* enable CBIE & CBCFE & CBZE on lower priviledge */
304     envcfg |= (3 << 4 | 1 << 6 | 1 << 7);
305     __set_MENVCFG(envcfg);
306 #endif
307 #endif
308 
309     cache_init();
310     section_init();
311     pmp_init();
312 
313     interrupt_init();
314     soc_set_sys_freq(20000000);
315     csi_tick_init();
316 
317 #if CONFIG_ECC_L2_ENABLE
318     extern void ecc_l2_irqhandler(void *arg);
319     /* l2 cache ecc interrupt register */
320     ecc_l2_dev.irq_num = L2_CACHE_ECC_IRQn;
321     csi_irq_attach(ecc_l2_dev.irq_num, ecc_l2_irqhandler, &ecc_l2_dev);
322     csi_irq_enable(ecc_l2_dev.irq_num);
323 #endif
324 }
325