blob: f97245605fac5cb561ef261d206fee8f8a74f114 [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) {
44 printf("error: pmp_size is not 2^n\n");
45 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
85 PMP_PRINT("AOCPU: configure PMP for memory 0x%lx ~ 0x%lx\n",
86 start_text_addr, end_text_addr);
87
88 while (text_len_left > 0) {
bangzheng.liu780b0652024-06-18 20:39:50 +080089 if ((text_len_left >= SIZE_64K) && ((pmp_region_base & (SIZE_64K - 1)) == 0))
90 next_seg_len = SIZE_64K;
91 else if ((text_len_left >= SIZE_32K) && ((pmp_region_base & (SIZE_32K - 1)) == 0))
bangzheng.liua87a98d2023-12-22 09:45:11 +080092 next_seg_len = SIZE_32K;
93 else if ((text_len_left >= SIZE_16K) && ((pmp_region_base & (SIZE_16K - 1)) == 0))
94 next_seg_len = SIZE_16K;
95 else if ((text_len_left >= SIZE_8K) && ((pmp_region_base & (SIZE_8K - 1)) == 0))
96 next_seg_len = SIZE_8K;
97 else if ((text_len_left >= SIZE_4K) && ((pmp_region_base & (SIZE_4K - 1)) == 0))
98 next_seg_len = SIZE_4K;
99 else if ((text_len_left >= SIZE_2K) && ((pmp_region_base & (SIZE_2K - 1)) == 0))
100 next_seg_len = SIZE_2K;
101 else if ((text_len_left >= SIZE_1K) && ((pmp_region_base & (SIZE_1K - 1)) == 0))
102 next_seg_len = SIZE_1K;
bangzheng.liuba6936f2023-09-20 17:39:09 +0800103
bangzheng.liua87a98d2023-12-22 09:45:11 +0800104 if (next_seg_len == 0) {
105 PMP_PRINT("pmp config error: not aligned.\n");
106 PMP_PRINT("pmp base: 0x%x, segment left: 0x%x\n",
107 pmp_region_base, text_len_left);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800108 break;
109 }
bangzheng.liua87a98d2023-12-22 09:45:11 +0800110
111 text_len_left -= next_seg_len;
112 PMP_PRINT_DEBUG("pm pregion base: %lx\n", pmp_region_base);
113 PMP_PRINT_DEBUG("segment length : %lx\n", next_seg_len);
114 PMP_PRINT_DEBUG("length left : %lx\n", text_len_left);
115
116 pmp_addr[pmp_entry_used] = pmpaddr_encode(pmp_region_base,
117 pmpcfg_order_get(next_seg_len));
118 pmp_cfg[pmp_entry_used] = (PMP_CFG_R_EN | PMP_CFG_X_EN |
119 PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800120 pmp_entry_used++;
121 pmp_region_base += next_seg_len;
122 PMP_PRINT_DEBUG("pmp_entry_used : %d\n", pmp_entry_used);
bangzheng.liua87a98d2023-12-22 09:45:11 +0800123 next_seg_len = 0;
124
125 if (pmp_entry_used >= 8) {
126 PMP_PRINT_DEBUG("Note: pmp entry has been full used\n");
127 break;
128 }
bangzheng.liuba6936f2023-09-20 17:39:09 +0800129 }
130
bangzheng.liua87a98d2023-12-22 09:45:11 +0800131 write_csr(pmpaddr0, pmp_addr[0]);
132 write_csr(pmpaddr1, pmp_addr[1]);
133 write_csr(pmpaddr2, pmp_addr[2]);
134 write_csr(pmpaddr3, pmp_addr[3]);
135 write_csr(pmpaddr4, pmp_addr[4]);
136 write_csr(pmpaddr5, pmp_addr[5]);
137 write_csr(pmpaddr6, pmp_addr[6]);
138 write_csr(pmpaddr7, pmp_addr[7]);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800139 PMP_PRINT_DEBUG("pmpaddr0 : %lx\n", read_csr(pmpaddr0));
140 PMP_PRINT_DEBUG("pmpaddr1 : %lx\n", read_csr(pmpaddr1));
141 PMP_PRINT_DEBUG("pmpaddr2 : %lx\n", read_csr(pmpaddr2));
142 PMP_PRINT_DEBUG("pmpaddr3 : %lx\n", read_csr(pmpaddr3));
143 PMP_PRINT_DEBUG("pmpaddr4 : %lx\n", read_csr(pmpaddr4));
144 PMP_PRINT_DEBUG("pmpaddr5 : %lx\n", read_csr(pmpaddr5));
145 PMP_PRINT_DEBUG("pmpaddr6 : %lx\n", read_csr(pmpaddr6));
146 PMP_PRINT_DEBUG("pmpaddr7 : %lx\n", read_csr(pmpaddr7));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800147
148 write_csr(pmpcfg0, (pmp_cfg[3] << 24) | (pmp_cfg[2] << 16) |
149 (pmp_cfg[1] << 8) | (pmp_cfg[0] << 0));
bangzheng.liuba6936f2023-09-20 17:39:09 +0800150 PMP_PRINT_DEBUG("pmpcfg0 : %lx\n", read_csr(pmpcfg0));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800151
152 write_csr(pmpcfg1, (pmp_cfg[7] << 24) | (pmp_cfg[6] << 16) |
153 (pmp_cfg[5] << 8) | (pmp_cfg[4] << 0));
bangzheng.liuba6936f2023-09-20 17:39:09 +0800154 PMP_PRINT_DEBUG("pmpcfg1 : %lx\n", read_csr(pmpcfg1));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800155
bangzheng.liuba6936f2023-09-20 17:39:09 +0800156 PMP_PRINT("AOCPU: configure PMP end\n");
157
158 return 0;
159}
160#endif
161
xiaohu.huang38262102022-05-06 22:21:48 +0800162void switch_m2u_mode(void)
163{
164 clear_csr(mstatus, MSTATUS_MPP);
165 //printf("\nIn the m2u function, the mstatus is 0x%x\n", read_csr(mstatus));
166 //printf("\nIn the m2u function, the mepc is 0x%x\n", read_csr(mepc));
167 asm volatile("la x6, 1f " ::: "x6");
168 asm volatile("csrw mepc, x6" :::);
169 asm volatile("mret" :::);
170 asm volatile("1:" :::);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800171}
172
173uint32_t mtime_lo(void)
174{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800175#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800176 return *(volatile uint32_t *)TIMERE_LOW_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800177#else
xiaohu.huang38262102022-05-06 22:21:48 +0800178 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800179#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800180}
181
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800182uint32_t mtime_hi(void)
183{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800184#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800185 return *(volatile uint32_t *)TIMERE_HIG_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800186#else
xiaohu.huang38262102022-05-06 22:21:48 +0800187 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800188#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800189}
190
191uint64_t get_timer_value(void)
192{
xiaohu.huang38262102022-05-06 22:21:48 +0800193 while (1) {
194 uint32_t hi = mtime_hi();
195 uint32_t lo = mtime_lo();
196
197 if (hi == mtime_hi())
198 return ((uint64_t)hi << 32) | lo;
199 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800200}
201
202uint32_t get_timer_freq(void)
203{
xiaohu.huang38262102022-05-06 22:21:48 +0800204 return TIMER_FREQ;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800205}
206
207uint64_t get_instret_value(void)
208{
xiaohu.huang38262102022-05-06 22:21:48 +0800209 while (1) {
210 uint32_t hi = read_csr(minstreth);
211 uint32_t lo = read_csr(minstret);
212
213 if (hi == read_csr(minstreth))
214 return ((uint64_t)hi << 32) | lo;
215 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800216}
217
218uint64_t get_cycle_value(void)
219{
xiaohu.huang38262102022-05-06 22:21:48 +0800220 while (1) {
221 uint32_t hi = read_csr(mcycleh);
222 uint32_t lo = read_csr(mcycle);
223
224 if (hi == read_csr(mcycleh))
225 return ((uint64_t)hi << 32) | lo;
226 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800227}
228
229unsigned long interrupt_status_get(void)
230{
231 return read_csr(mstatus) >> 0x3;
232}
233
234void interrupt_disable(void)
235{
236 clear_csr(mstatus, MSTATUS_MIE);
237}
238
239void interrupt_enable(void)
240{
241 set_csr(mstatus, MSTATUS_MIE);
242}
243
244#ifndef CONFIG_N200_REVA
245
xiaohu.huang38262102022-05-06 22:21:48 +0800246uint32_t __noinline measure_cpu_freq(size_t n)
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800247{
xiaohu.huang38262102022-05-06 22:21:48 +0800248 uint32_t start_mtime, delta_mtime;
249 uint32_t mtime_freq = get_timer_freq();
250 // Don't start measuruing until we see an mtime tick
251 uint32_t tmp = mtime_lo();
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800252
xiaohu.huang38262102022-05-06 22:21:48 +0800253 do {
254 start_mtime = mtime_lo();
255 } while (start_mtime == tmp);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800256
xiaohu.huang38262102022-05-06 22:21:48 +0800257 uint32_t start_mcycle = read_csr(mcycle);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800258
xiaohu.huang38262102022-05-06 22:21:48 +0800259 do {
260 delta_mtime = mtime_lo() - start_mtime;
261 } while (delta_mtime < n);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800262
xiaohu.huang38262102022-05-06 22:21:48 +0800263 uint32_t delta_mcycle = read_csr(mcycle) - start_mcycle;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800264
xiaohu.huang38262102022-05-06 22:21:48 +0800265 return (delta_mcycle / delta_mtime) * mtime_freq +
266 ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800267}
268
269uint32_t get_cpu_freq(void)
270{
xiaohu.huang38262102022-05-06 22:21:48 +0800271 uint32_t cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800272
xiaohu.huang38262102022-05-06 22:21:48 +0800273 // warm up
274 measure_cpu_freq(1);
275 // measure for real
276 cpu_freq = measure_cpu_freq(100);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800277
xiaohu.huang38262102022-05-06 22:21:48 +0800278 return cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800279}
280
281unsigned int xPortIsIsrContext(void)
282{
283 return (read_csr_msubmode & 0xff);
284}
285
286#else
287
288unsigned int xPortIsIsrContext(void)
289{
290 return read_csr_msubmode;
291}
292
293#endif