blob: 0ae0bf0bd08a8e8d52698f6554693be27a29d86f [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.liua87a98d2023-12-22 09:45:11 +080089 if ((text_len_left >= SIZE_32K) && ((pmp_region_base & (SIZE_32K - 1)) == 0))
90 next_seg_len = SIZE_32K;
91 else if ((text_len_left >= SIZE_16K) && ((pmp_region_base & (SIZE_16K - 1)) == 0))
92 next_seg_len = SIZE_16K;
93 else if ((text_len_left >= SIZE_8K) && ((pmp_region_base & (SIZE_8K - 1)) == 0))
94 next_seg_len = SIZE_8K;
95 else if ((text_len_left >= SIZE_4K) && ((pmp_region_base & (SIZE_4K - 1)) == 0))
96 next_seg_len = SIZE_4K;
97 else if ((text_len_left >= SIZE_2K) && ((pmp_region_base & (SIZE_2K - 1)) == 0))
98 next_seg_len = SIZE_2K;
99 else if ((text_len_left >= SIZE_1K) && ((pmp_region_base & (SIZE_1K - 1)) == 0))
100 next_seg_len = SIZE_1K;
bangzheng.liuba6936f2023-09-20 17:39:09 +0800101
bangzheng.liua87a98d2023-12-22 09:45:11 +0800102 if (next_seg_len == 0) {
103 PMP_PRINT("pmp config error: not aligned.\n");
104 PMP_PRINT("pmp base: 0x%x, segment left: 0x%x\n",
105 pmp_region_base, text_len_left);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800106 break;
107 }
bangzheng.liua87a98d2023-12-22 09:45:11 +0800108
109 text_len_left -= next_seg_len;
110 PMP_PRINT_DEBUG("pm pregion base: %lx\n", pmp_region_base);
111 PMP_PRINT_DEBUG("segment length : %lx\n", next_seg_len);
112 PMP_PRINT_DEBUG("length left : %lx\n", text_len_left);
113
114 pmp_addr[pmp_entry_used] = pmpaddr_encode(pmp_region_base,
115 pmpcfg_order_get(next_seg_len));
116 pmp_cfg[pmp_entry_used] = (PMP_CFG_R_EN | PMP_CFG_X_EN |
117 PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800118 pmp_entry_used++;
119 pmp_region_base += next_seg_len;
120 PMP_PRINT_DEBUG("pmp_entry_used : %d\n", pmp_entry_used);
bangzheng.liua87a98d2023-12-22 09:45:11 +0800121 next_seg_len = 0;
122
123 if (pmp_entry_used >= 8) {
124 PMP_PRINT_DEBUG("Note: pmp entry has been full used\n");
125 break;
126 }
bangzheng.liuba6936f2023-09-20 17:39:09 +0800127 }
128
bangzheng.liua87a98d2023-12-22 09:45:11 +0800129 write_csr(pmpaddr0, pmp_addr[0]);
130 write_csr(pmpaddr1, pmp_addr[1]);
131 write_csr(pmpaddr2, pmp_addr[2]);
132 write_csr(pmpaddr3, pmp_addr[3]);
133 write_csr(pmpaddr4, pmp_addr[4]);
134 write_csr(pmpaddr5, pmp_addr[5]);
135 write_csr(pmpaddr6, pmp_addr[6]);
136 write_csr(pmpaddr7, pmp_addr[7]);
bangzheng.liuba6936f2023-09-20 17:39:09 +0800137 PMP_PRINT_DEBUG("pmpaddr0 : %lx\n", read_csr(pmpaddr0));
138 PMP_PRINT_DEBUG("pmpaddr1 : %lx\n", read_csr(pmpaddr1));
139 PMP_PRINT_DEBUG("pmpaddr2 : %lx\n", read_csr(pmpaddr2));
140 PMP_PRINT_DEBUG("pmpaddr3 : %lx\n", read_csr(pmpaddr3));
141 PMP_PRINT_DEBUG("pmpaddr4 : %lx\n", read_csr(pmpaddr4));
142 PMP_PRINT_DEBUG("pmpaddr5 : %lx\n", read_csr(pmpaddr5));
143 PMP_PRINT_DEBUG("pmpaddr6 : %lx\n", read_csr(pmpaddr6));
144 PMP_PRINT_DEBUG("pmpaddr7 : %lx\n", read_csr(pmpaddr7));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800145
146 write_csr(pmpcfg0, (pmp_cfg[3] << 24) | (pmp_cfg[2] << 16) |
147 (pmp_cfg[1] << 8) | (pmp_cfg[0] << 0));
bangzheng.liuba6936f2023-09-20 17:39:09 +0800148 PMP_PRINT_DEBUG("pmpcfg0 : %lx\n", read_csr(pmpcfg0));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800149
150 write_csr(pmpcfg1, (pmp_cfg[7] << 24) | (pmp_cfg[6] << 16) |
151 (pmp_cfg[5] << 8) | (pmp_cfg[4] << 0));
bangzheng.liuba6936f2023-09-20 17:39:09 +0800152 PMP_PRINT_DEBUG("pmpcfg1 : %lx\n", read_csr(pmpcfg1));
bangzheng.liua87a98d2023-12-22 09:45:11 +0800153
bangzheng.liuba6936f2023-09-20 17:39:09 +0800154 PMP_PRINT("AOCPU: configure PMP end\n");
155
156 return 0;
157}
158#endif
159
xiaohu.huang38262102022-05-06 22:21:48 +0800160void switch_m2u_mode(void)
161{
162 clear_csr(mstatus, MSTATUS_MPP);
163 //printf("\nIn the m2u function, the mstatus is 0x%x\n", read_csr(mstatus));
164 //printf("\nIn the m2u function, the mepc is 0x%x\n", read_csr(mepc));
165 asm volatile("la x6, 1f " ::: "x6");
166 asm volatile("csrw mepc, x6" :::);
167 asm volatile("mret" :::);
168 asm volatile("1:" :::);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800169}
170
171uint32_t mtime_lo(void)
172{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800173#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800174 return *(volatile uint32_t *)TIMERE_LOW_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800175#else
xiaohu.huang38262102022-05-06 22:21:48 +0800176 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800177#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800178}
179
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800180uint32_t mtime_hi(void)
181{
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800182#ifdef configSOC_TIMER_AS_TICK
xiaohu.huang38262102022-05-06 22:21:48 +0800183 return *(volatile uint32_t *)TIMERE_HIG_REG;
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800184#else
xiaohu.huang38262102022-05-06 22:21:48 +0800185 return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4);
Xiaohu.Huanga2c5a042022-03-12 22:41:09 +0800186#endif
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800187}
188
189uint64_t get_timer_value(void)
190{
xiaohu.huang38262102022-05-06 22:21:48 +0800191 while (1) {
192 uint32_t hi = mtime_hi();
193 uint32_t lo = mtime_lo();
194
195 if (hi == mtime_hi())
196 return ((uint64_t)hi << 32) | lo;
197 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800198}
199
200uint32_t get_timer_freq(void)
201{
xiaohu.huang38262102022-05-06 22:21:48 +0800202 return TIMER_FREQ;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800203}
204
205uint64_t get_instret_value(void)
206{
xiaohu.huang38262102022-05-06 22:21:48 +0800207 while (1) {
208 uint32_t hi = read_csr(minstreth);
209 uint32_t lo = read_csr(minstret);
210
211 if (hi == read_csr(minstreth))
212 return ((uint64_t)hi << 32) | lo;
213 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800214}
215
216uint64_t get_cycle_value(void)
217{
xiaohu.huang38262102022-05-06 22:21:48 +0800218 while (1) {
219 uint32_t hi = read_csr(mcycleh);
220 uint32_t lo = read_csr(mcycle);
221
222 if (hi == read_csr(mcycleh))
223 return ((uint64_t)hi << 32) | lo;
224 }
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800225}
226
227unsigned long interrupt_status_get(void)
228{
229 return read_csr(mstatus) >> 0x3;
230}
231
232void interrupt_disable(void)
233{
234 clear_csr(mstatus, MSTATUS_MIE);
235}
236
237void interrupt_enable(void)
238{
239 set_csr(mstatus, MSTATUS_MIE);
240}
241
242#ifndef CONFIG_N200_REVA
243
xiaohu.huang38262102022-05-06 22:21:48 +0800244uint32_t __noinline measure_cpu_freq(size_t n)
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800245{
xiaohu.huang38262102022-05-06 22:21:48 +0800246 uint32_t start_mtime, delta_mtime;
247 uint32_t mtime_freq = get_timer_freq();
248 // Don't start measuruing until we see an mtime tick
249 uint32_t tmp = mtime_lo();
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800250
xiaohu.huang38262102022-05-06 22:21:48 +0800251 do {
252 start_mtime = mtime_lo();
253 } while (start_mtime == tmp);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800254
xiaohu.huang38262102022-05-06 22:21:48 +0800255 uint32_t start_mcycle = read_csr(mcycle);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800256
xiaohu.huang38262102022-05-06 22:21:48 +0800257 do {
258 delta_mtime = mtime_lo() - start_mtime;
259 } while (delta_mtime < n);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800260
xiaohu.huang38262102022-05-06 22:21:48 +0800261 uint32_t delta_mcycle = read_csr(mcycle) - start_mcycle;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800262
xiaohu.huang38262102022-05-06 22:21:48 +0800263 return (delta_mcycle / delta_mtime) * mtime_freq +
264 ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800265}
266
267uint32_t get_cpu_freq(void)
268{
xiaohu.huang38262102022-05-06 22:21:48 +0800269 uint32_t cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800270
xiaohu.huang38262102022-05-06 22:21:48 +0800271 // warm up
272 measure_cpu_freq(1);
273 // measure for real
274 cpu_freq = measure_cpu_freq(100);
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800275
xiaohu.huang38262102022-05-06 22:21:48 +0800276 return cpu_freq;
Xiaohu.Huangf78b48b2022-01-17 10:41:38 +0800277}
278
279unsigned int xPortIsIsrContext(void)
280{
281 return (read_csr_msubmode & 0xff);
282}
283
284#else
285
286unsigned int xPortIsIsrContext(void)
287{
288 return read_csr_msubmode;
289}
290
291#endif