blob: e7532e97e20f7d9d774c1748637e8a6ca02a0831 [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
39/*
40 * -- Configure PMP --
41 * For both Machine and User mode.
42 * To make aocpu text/ro data space readable and executable.
43 * To make aocpu data space readable and writable.
44 * To make 4G space readable and writable.
45 * Note:
46 * If config_pmp is called, pmp_open_all_space is invalid.
47 */
48uint32_t config_pmp(void)
49{
50 uint32_t start_text_addr = (uint32_t)&_text;
51 uint32_t end_text_addr = (uint32_t)&_etext;
52 uint32_t text_len_left = end_text_addr - start_text_addr;
53 uint32_t next_seg_len;
54 uint32_t pmp_cfg[8] = {0};
55 int pmp_entry_used = 0;
56 uint32_t pmp_region_base = start_text_addr;
57 uint32_t ao_ram_end = configMEM_START + configMEM_LEN;
58 uint32_t all_region_size = 0x1fffffff;
59
60 PMP_PRINT("AOCPU: configure PMP for memory 0x%lx ~ 0x%lx\n",
61 start_text_addr, end_text_addr);
62
63 while (text_len_left > 0) {
64 for (next_seg_len = 1024; next_seg_len*2 <= text_len_left; next_seg_len *= 2)
65 ;
66
67 text_len_left -= next_seg_len;
68 PMP_PRINT_DEBUG("segment length: %lx\n", next_seg_len);
69 PMP_PRINT_DEBUG("length left : %lx\n", text_len_left);
70
71 /* Configure text/ro data space access privilege */
72 switch (pmp_entry_used) {
73 case 0:
74 write_csr(pmpaddr0, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
75 pmp_cfg[0] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
76 break;
77 case 1:
78 write_csr(pmpaddr1, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
79 pmp_cfg[1] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
80 break;
81 case 2:
82 write_csr(pmpaddr2, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
83 pmp_cfg[2] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
84 break;
85 case 3:
86 write_csr(pmpaddr3, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
87 pmp_cfg[3] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
88 break;
89 case 4:
90 write_csr(pmpaddr4, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
91 pmp_cfg[4] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
92 break;
93 case 5:
94 write_csr(pmpaddr5, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
95 pmp_cfg[5] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
96 break;
97 default:
98 break;
99 }
100 pmp_entry_used++;
101 pmp_region_base += next_seg_len;
102 PMP_PRINT_DEBUG("pmp_entry_used : %d\n", pmp_entry_used);
103 PMP_PRINT_DEBUG("pmp_region_base: %lx\n", pmp_region_base);
104 }
105
106 /* Configure data space access privilege */
107 write_csr(pmpaddr6, (pmp_region_base >> 2) | NAPOT_SIZE(ao_ram_end - pmp_region_base));
108 pmp_cfg[6] = (PMP_CFG_R_EN | PMP_CFG_W_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
109 /* Configure all 32-bit (4G) address space access privilege */
110 write_csr(pmpaddr7, (0x0) | all_region_size);
111 pmp_cfg[7] = (PMP_CFG_R_EN | PMP_CFG_W_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
112 /* Set Configuration for text/ro data/data/4G space */
113 write_csr(pmpcfg0, (pmp_cfg[3] << 24) | (pmp_cfg[2] << 16) |
114 (pmp_cfg[1] << 8) | (pmp_cfg[0] << 0));
115 write_csr(pmpcfg1, (pmp_cfg[7] << 24) | (pmp_cfg[6] << 16) |
116 (pmp_cfg[5] << 8) | (pmp_cfg[4] << 0));
117
118 PMP_PRINT_DEBUG("pmpaddr0 : %lx\n", read_csr(pmpaddr0));
119 PMP_PRINT_DEBUG("pmpaddr1 : %lx\n", read_csr(pmpaddr1));
120 PMP_PRINT_DEBUG("pmpaddr2 : %lx\n", read_csr(pmpaddr2));
121 PMP_PRINT_DEBUG("pmpaddr3 : %lx\n", read_csr(pmpaddr3));
122 PMP_PRINT_DEBUG("pmpaddr4 : %lx\n", read_csr(pmpaddr4));
123 PMP_PRINT_DEBUG("pmpaddr5 : %lx\n", read_csr(pmpaddr5));
124 PMP_PRINT_DEBUG("pmpaddr6 : %lx\n", read_csr(pmpaddr6));
125 PMP_PRINT_DEBUG("pmpaddr7 : %lx\n", read_csr(pmpaddr7));
126 PMP_PRINT_DEBUG("pmpcfg0 : %lx\n", read_csr(pmpcfg0));
127 PMP_PRINT_DEBUG("pmpcfg1 : %lx\n", read_csr(pmpcfg1));
128 PMP_PRINT("AOCPU: configure PMP end\n");
129
130 return 0;
131}
132#endif
133
xiaohu.huang38262102022-05-06 22:21:48 +0800134void switch_m2u_mode(void)
135{
136 clear_csr(mstatus, MSTATUS_MPP);
137 //printf("\nIn the m2u function, the mstatus is 0x%x\n", read_csr(mstatus));
138 //printf("\nIn the m2u function, the mepc is 0x%x\n", read_csr(mepc));
139 asm volatile("la x6, 1f " ::: "x6");
140 asm volatile("csrw mepc, x6" :::);
141 asm volatile("mret" :::);
142 asm volatile("1:" :::);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800143}
144
145uint32_t mtime_lo(void)
146{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800147#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800148 return *(volatile uint32_t *)TIMERE_LOW_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800149#else
xiaohu.huang38262102022-05-06 22:21:48 +0800150 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800151#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800152}
153
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800154uint32_t mtime_hi(void)
155{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800156#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800157 return *(volatile uint32_t *)TIMERE_HIG_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800158#else
xiaohu.huang38262102022-05-06 22:21:48 +0800159 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800160#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800161}
162
163uint64_t get_timer_value(void)
164{
xiaohu.huang38262102022-05-06 22:21:48 +0800165 while (1) {
166 uint32_t hi = mtime_hi();
167 uint32_t lo = mtime_lo();
168
169 if (hi == mtime_hi())
170 return ((uint64_t)hi << 32) | lo;
171 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800172}
173
174uint32_t get_timer_freq(void)
175{
xiaohu.huang38262102022-05-06 22:21:48 +0800176 return TIMER_FREQ;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800177}
178
179uint64_t get_instret_value(void)
180{
xiaohu.huang38262102022-05-06 22:21:48 +0800181 while (1) {
182 uint32_t hi = read_csr(minstreth);
183 uint32_t lo = read_csr(minstret);
184
185 if (hi == read_csr(minstreth))
186 return ((uint64_t)hi << 32) | lo;
187 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800188}
189
190uint64_t get_cycle_value(void)
191{
xiaohu.huang38262102022-05-06 22:21:48 +0800192 while (1) {
193 uint32_t hi = read_csr(mcycleh);
194 uint32_t lo = read_csr(mcycle);
195
196 if (hi == read_csr(mcycleh))
197 return ((uint64_t)hi << 32) | lo;
198 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800199}
200
201unsigned long interrupt_status_get(void)
202{
203 return read_csr(mstatus) >> 0x3;
204}
205
206void interrupt_disable(void)
207{
208 clear_csr(mstatus, MSTATUS_MIE);
209}
210
211void interrupt_enable(void)
212{
213 set_csr(mstatus, MSTATUS_MIE);
214}
215
216#ifndef CONFIG_N200_REVA
217
xiaohu.huang38262102022-05-06 22:21:48 +0800218uint32_t __noinline measure_cpu_freq(size_t n)
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800219{
xiaohu.huang38262102022-05-06 22:21:48 +0800220 uint32_t start_mtime, delta_mtime;
221 uint32_t mtime_freq = get_timer_freq();
222 // Don't start measuruing until we see an mtime tick
223 uint32_t tmp = mtime_lo();
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800224
xiaohu.huang38262102022-05-06 22:21:48 +0800225 do {
226 start_mtime = mtime_lo();
227 } while (start_mtime == tmp);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800228
xiaohu.huang38262102022-05-06 22:21:48 +0800229 uint32_t start_mcycle = read_csr(mcycle);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800230
xiaohu.huang38262102022-05-06 22:21:48 +0800231 do {
232 delta_mtime = mtime_lo() - start_mtime;
233 } while (delta_mtime < n);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800234
xiaohu.huang38262102022-05-06 22:21:48 +0800235 uint32_t delta_mcycle = read_csr(mcycle) - start_mcycle;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800236
xiaohu.huang38262102022-05-06 22:21:48 +0800237 return (delta_mcycle / delta_mtime) * mtime_freq +
238 ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800239}
240
241uint32_t get_cpu_freq(void)
242{
xiaohu.huang38262102022-05-06 22:21:48 +0800243 uint32_t cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800244
xiaohu.huang38262102022-05-06 22:21:48 +0800245 // warm up
246 measure_cpu_freq(1);
247 // measure for real
248 cpu_freq = measure_cpu_freq(100);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800249
xiaohu.huang38262102022-05-06 22:21:48 +0800250 return cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800251}
252
253unsigned int xPortIsIsrContext(void)
254{
255 return (read_csr_msubmode & 0xff);
256}
257
258#else
259
260unsigned int xPortIsIsrContext(void)
261{
262 return read_csr_msubmode;
263}
264
265#endif