blob: 94f6272b0d801f877f7545f28537cbf1325919ee [file] [log] [blame]
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +08001/*
2 * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#include "n200_func.h"
13#include "register.h"
14#include "common.h"
15#include "n200_timer.h"
xiaohu.huang38262102022-05-06 22:21:48 +080016#include "gcc_compiler_attributes.h"
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +080017#include "riscv_encoding.h"
bangzheng.liuba6936f2023-09-20 17:39:09 +080018#include "lscript.h"
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +080019
bangzheng.liuba6936f2023-09-20 17:39:09 +080020#define PMP_PRINT(...) printf(__VA_ARGS__)
21#define PMP_PRINT_DEBUG(...) //printf(__VA_ARGS__)
22
23/*
24 * -- Configure PMP --
25 * For User mode only.
26 * To make all the address space accessible and executable
27 */
xiaohu.huang38262102022-05-06 22:21:48 +080028void pmp_open_all_space(void)
29{
30 // Config entry0 addr to all 1s to make the range cover all space
bangzheng.liuba6936f2023-09-20 17:39:09 +080031 asm volatile ("li x6, 0xffffffff":::"x6");
32 asm volatile ("csrw pmpaddr0, x6":::);
xiaohu.huang38262102022-05-06 22:21:48 +080033 // Config entry0 cfg to make it NAPOT address mode, and R/W/X okay
bangzheng.liuba6936f2023-09-20 17:39:09 +080034 asm volatile ("li x6, 0x7f":::"x6");
35 asm volatile ("csrw pmpcfg0, x6":::);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +080036}
37
bangzheng.liuba6936f2023-09-20 17:39:09 +080038#ifndef CONFIG_N200_REVA
bangzheng.liua87a98d2023-12-22 09:45:11 +080039static uint32_t pmpcfg_order_get(uint32_t pmp_size)
40{
41 int pmpcfg_order = 0;
42
43 if ((pmp_size & (pmp_size - 1)) != 0) {
bangzheng.liu239de842024-12-04 18:27:21 +080044 PMP_PRINT("err: pmp_size is not 2^n\n");
bangzheng.liua87a98d2023-12-22 09:45:11 +080045 return 0;
46 }
47
48 while (pmp_size > 1) {
49 pmp_size >>= 1;
50 pmpcfg_order++;
51 }
52
53 return pmpcfg_order;
54}
55
56static uint32_t pmpaddr_encode(uint32_t pmp_base_addr, uint32_t pmp_cfg_order)
57{
58 uint32_t addrmask, pmpaddr;
59
60 addrmask = (1UL << (pmp_cfg_order - PMP_SHIFT)) - 1;
61 pmpaddr = ((pmp_base_addr >> PMP_SHIFT) & ~addrmask);
62 pmpaddr |= (addrmask >> 1);
63
64 return pmpaddr;
65}
66
67
bangzheng.liuba6936f2023-09-20 17:39:09 +080068/*
69 * -- Configure PMP --
70 * For both Machine and User mode.
71 * To make aocpu text/ro data space readable and executable.
bangzheng.liuba6936f2023-09-20 17:39:09 +080072 * Note:
bangzheng.liua87a98d2023-12-22 09:45:11 +080073 * If config_pmp is called, pmp_open_all_space is invalid.
bangzheng.liuba6936f2023-09-20 17:39:09 +080074 */
75uint32_t config_pmp(void)
76{
77 uint32_t start_text_addr = (uint32_t)&_text;
78 uint32_t end_text_addr = (uint32_t)&_etext;
79 uint32_t text_len_left = end_text_addr - start_text_addr;
bangzheng.liua87a98d2023-12-22 09:45:11 +080080 uint32_t next_seg_len = 0;
81 uint32_t pmp_cfg[8] = {0}, pmp_addr[8] = {0};
bangzheng.liuba6936f2023-09-20 17:39:09 +080082 int pmp_entry_used = 0;
83 uint32_t pmp_region_base = start_text_addr;
bangzheng.liuba6936f2023-09-20 17:39:09 +080084
bangzheng.liu239de842024-12-04 18:27:21 +080085 PMP_PRINT("PMP config range %lx ~ %lx\n", start_text_addr, end_text_addr);
bangzheng.liuba6936f2023-09-20 17:39:09 +080086
87 while (text_len_left > 0) {
bangzheng.liu780b0652024-06-18 20:39:50 +080088 if ((text_len_left >= SIZE_64K) && ((pmp_region_base & (SIZE_64K - 1)) == 0))
89 next_seg_len = SIZE_64K;
90 else if ((text_len_left >= SIZE_32K) && ((pmp_region_base & (SIZE_32K - 1)) == 0))
bangzheng.liua87a98d2023-12-22 09:45:11 +080091 next_seg_len = SIZE_32K;
92 else if ((text_len_left >= SIZE_16K) && ((pmp_region_base & (SIZE_16K - 1)) == 0))
93 next_seg_len = SIZE_16K;
94 else if ((text_len_left >= SIZE_8K) && ((pmp_region_base & (SIZE_8K - 1)) == 0))
95 next_seg_len = SIZE_8K;
96 else if ((text_len_left >= SIZE_4K) && ((pmp_region_base & (SIZE_4K - 1)) == 0))
97 next_seg_len = SIZE_4K;
98 else if ((text_len_left >= SIZE_2K) && ((pmp_region_base & (SIZE_2K - 1)) == 0))
99 next_seg_len = SIZE_2K;
100 else if ((text_len_left >= SIZE_1K) && ((pmp_region_base & (SIZE_1K - 1)) == 0))
101 next_seg_len = SIZE_1K;
bangzheng.liuba6936f2023-09-20 17:39:09 +0800102
bangzheng.liua87a98d2023-12-22 09:45:11 +0800103 if (next_seg_len == 0) {
bangzheng.liu239de842024-12-04 18:27:21 +0800104 PMP_PRINT("PMP config err: not align.\n");
105 PMP_PRINT_DEBUG("pmp base: 0x%x, segment left: 0x%x\n",
bangzheng.liua87a98d2023-12-22 09:45:11 +0800106 pmp_region_base, text_len_left);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800107 break;
108 }
bangzheng.liua87a98d2023-12-22 09:45:11 +0800109
110 text_len_left -= next_seg_len;
111 PMP_PRINT_DEBUG("pm pregion base: %lx\n", pmp_region_base);
112 PMP_PRINT_DEBUG("segment length : %lx\n", next_seg_len);
113 PMP_PRINT_DEBUG("length left : %lx\n", text_len_left);
114
115 pmp_addr[pmp_entry_used] = pmpaddr_encode(pmp_region_base,
116 pmpcfg_order_get(next_seg_len));
117 pmp_cfg[pmp_entry_used] = (PMP_CFG_R_EN | PMP_CFG_X_EN |
118 PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800119 pmp_entry_used++;
120 pmp_region_base += next_seg_len;
121 PMP_PRINT_DEBUG("pmp_entry_used : %d\n", pmp_entry_used);
bangzheng.liua87a98d2023-12-22 09:45:11 +0800122 next_seg_len = 0;
123
124 if (pmp_entry_used >= 8) {
125 PMP_PRINT_DEBUG("Note: pmp entry has been full used\n");
126 break;
127 }
bangzheng.liuba6936f2023-09-20 17:39:09 +0800128 }
129
bangzheng.liua87a98d2023-12-22 09:45:11 +0800130 write_csr(pmpaddr0, pmp_addr[0]);
131 write_csr(pmpaddr1, pmp_addr[1]);
132 write_csr(pmpaddr2, pmp_addr[2]);
133 write_csr(pmpaddr3, pmp_addr[3]);
134 write_csr(pmpaddr4, pmp_addr[4]);
135 write_csr(pmpaddr5, pmp_addr[5]);
136 write_csr(pmpaddr6, pmp_addr[6]);
137 write_csr(pmpaddr7, pmp_addr[7]);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800138 PMP_PRINT_DEBUG("pmpaddr0 : %lx\n", read_csr(pmpaddr0));
139 PMP_PRINT_DEBUG("pmpaddr1 : %lx\n", read_csr(pmpaddr1));
140 PMP_PRINT_DEBUG("pmpaddr2 : %lx\n", read_csr(pmpaddr2));
141 PMP_PRINT_DEBUG("pmpaddr3 : %lx\n", read_csr(pmpaddr3));
142 PMP_PRINT_DEBUG("pmpaddr4 : %lx\n", read_csr(pmpaddr4));
143 PMP_PRINT_DEBUG("pmpaddr5 : %lx\n", read_csr(pmpaddr5));
144 PMP_PRINT_DEBUG("pmpaddr6 : %lx\n", read_csr(pmpaddr6));
145 PMP_PRINT_DEBUG("pmpaddr7 : %lx\n", read_csr(pmpaddr7));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800146
147 write_csr(pmpcfg0, (pmp_cfg[3] << 24) | (pmp_cfg[2] << 16) |
148 (pmp_cfg[1] << 8) | (pmp_cfg[0] << 0));
bangzheng.liuba6936f2023-09-20 17:39:09 +0800149 PMP_PRINT_DEBUG("pmpcfg0 : %lx\n", read_csr(pmpcfg0));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800150
151 write_csr(pmpcfg1, (pmp_cfg[7] << 24) | (pmp_cfg[6] << 16) |
152 (pmp_cfg[5] << 8) | (pmp_cfg[4] << 0));
bangzheng.liuba6936f2023-09-20 17:39:09 +0800153 PMP_PRINT_DEBUG("pmpcfg1 : %lx\n", read_csr(pmpcfg1));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800154
bangzheng.liu239de842024-12-04 18:27:21 +0800155 PMP_PRINT("PMP config end\n");
bangzheng.liuba6936f2023-09-20 17:39:09 +0800156
157 return 0;
158}
bangzheng.liu17e86982024-06-18 20:04:34 +0800159
160#ifdef CONFIG_AOCPU_BUSRESPERR_DETECTION
161void config_eclic_busresperr_irq(void)
162{
163 /* enable bus response error interrupt for no access permission */
164 uint8_t bus_err_intattr;
165
166 bus_err_intattr = eclic_get_intattr(ECLIC_INT_BUS_RESP_ERR);
167 bus_err_intattr |= ECLIC_INT_ATTR_SHV | ECLIC_INT_ATTR_TRIG_EDGE;
168 eclic_set_intattr(ECLIC_INT_BUS_RESP_ERR, bus_err_intattr);
169 eclic_set_intctrl(ECLIC_INT_BUS_RESP_ERR, 15 << 4);
170 eclic_enable_interrupt(ECLIC_INT_BUS_RESP_ERR);
171
172}
173#endif
bangzheng.liuba6936f2023-09-20 17:39:09 +0800174#endif
175
xiaohu.huang38262102022-05-06 22:21:48 +0800176void switch_m2u_mode(void)
177{
178 clear_csr(mstatus, MSTATUS_MPP);
179 //printf("\nIn the m2u function, the mstatus is 0x%x\n", read_csr(mstatus));
180 //printf("\nIn the m2u function, the mepc is 0x%x\n", read_csr(mepc));
181 asm volatile("la x6, 1f " ::: "x6");
182 asm volatile("csrw mepc, x6" :::);
183 asm volatile("mret" :::);
184 asm volatile("1:" :::);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800185}
186
187uint32_t mtime_lo(void)
188{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800189#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800190 return *(volatile uint32_t *)TIMERE_LOW_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800191#else
xiaohu.huang38262102022-05-06 22:21:48 +0800192 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800193#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800194}
195
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800196uint32_t mtime_hi(void)
197{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800198#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800199 return *(volatile uint32_t *)TIMERE_HIG_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800200#else
xiaohu.huang38262102022-05-06 22:21:48 +0800201 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800202#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800203}
204
205uint64_t get_timer_value(void)
206{
xiaohu.huang38262102022-05-06 22:21:48 +0800207 while (1) {
208 uint32_t hi = mtime_hi();
209 uint32_t lo = mtime_lo();
210
211 if (hi == mtime_hi())
212 return ((uint64_t)hi << 32) | lo;
213 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800214}
215
216uint32_t get_timer_freq(void)
217{
xiaohu.huang38262102022-05-06 22:21:48 +0800218 return TIMER_FREQ;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800219}
220
221uint64_t get_instret_value(void)
222{
xiaohu.huang38262102022-05-06 22:21:48 +0800223 while (1) {
224 uint32_t hi = read_csr(minstreth);
225 uint32_t lo = read_csr(minstret);
226
227 if (hi == read_csr(minstreth))
228 return ((uint64_t)hi << 32) | lo;
229 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800230}
231
232uint64_t get_cycle_value(void)
233{
xiaohu.huang38262102022-05-06 22:21:48 +0800234 while (1) {
235 uint32_t hi = read_csr(mcycleh);
236 uint32_t lo = read_csr(mcycle);
237
238 if (hi == read_csr(mcycleh))
239 return ((uint64_t)hi << 32) | lo;
240 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800241}
242
243unsigned long interrupt_status_get(void)
244{
245 return read_csr(mstatus) >> 0x3;
246}
247
248void interrupt_disable(void)
249{
250 clear_csr(mstatus, MSTATUS_MIE);
251}
252
253void interrupt_enable(void)
254{
255 set_csr(mstatus, MSTATUS_MIE);
256}
257
258#ifndef CONFIG_N200_REVA
259
xiaohu.huang38262102022-05-06 22:21:48 +0800260uint32_t __noinline measure_cpu_freq(size_t n)
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800261{
xiaohu.huang38262102022-05-06 22:21:48 +0800262 uint32_t start_mtime, delta_mtime;
263 uint32_t mtime_freq = get_timer_freq();
264 // Don't start measuruing until we see an mtime tick
265 uint32_t tmp = mtime_lo();
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800266
xiaohu.huang38262102022-05-06 22:21:48 +0800267 do {
268 start_mtime = mtime_lo();
269 } while (start_mtime == tmp);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800270
xiaohu.huang38262102022-05-06 22:21:48 +0800271 uint32_t start_mcycle = read_csr(mcycle);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800272
xiaohu.huang38262102022-05-06 22:21:48 +0800273 do {
274 delta_mtime = mtime_lo() - start_mtime;
275 } while (delta_mtime < n);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800276
xiaohu.huang38262102022-05-06 22:21:48 +0800277 uint32_t delta_mcycle = read_csr(mcycle) - start_mcycle;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800278
xiaohu.huang38262102022-05-06 22:21:48 +0800279 return (delta_mcycle / delta_mtime) * mtime_freq +
280 ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800281}
282
283uint32_t get_cpu_freq(void)
284{
xiaohu.huang38262102022-05-06 22:21:48 +0800285 uint32_t cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800286
xiaohu.huang38262102022-05-06 22:21:48 +0800287 // warm up
288 measure_cpu_freq(1);
289 // measure for real
290 cpu_freq = measure_cpu_freq(100);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800291
xiaohu.huang38262102022-05-06 22:21:48 +0800292 return cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800293}
294
295unsigned int xPortIsIsrContext(void)
296{
297 return (read_csr_msubmode & 0xff);
298}
299
300#else
301
302unsigned int xPortIsIsrContext(void)
303{
304 return read_csr_msubmode;
305}
306
307#endif