blob: 492b6245b405d72d9899979f6f494eb4974ebb11 [file] [log] [blame]
/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "n200_func.h"
#include "register.h"
#include "common.h"
#include "n200_timer.h"
#include "gcc_compiler_attributes.h"
#include "riscv_encoding.h"
// Configure PMP to make all the address space accesable and executable
void pmp_open_all_space(void)
{
// Config entry0 addr to all 1s to make the range cover all space
asm volatile("li x6, 0xffffffff" ::: "x6");
asm volatile("csrw pmpaddr0, x6" :::);
// Config entry0 cfg to make it NAPOT address mode, and R/W/X okay
asm volatile("li x6, 0x7f" ::: "x6");
asm volatile("csrw pmpcfg0, x6" :::);
}
void switch_m2u_mode(void)
{
clear_csr(mstatus, MSTATUS_MPP);
//printf("\nIn the m2u function, the mstatus is 0x%x\n", read_csr(mstatus));
//printf("\nIn the m2u function, the mepc is 0x%x\n", read_csr(mepc));
asm volatile("la x6, 1f " ::: "x6");
asm volatile("csrw mepc, x6" :::);
asm volatile("mret" :::);
asm volatile("1:" :::);
}
uint32_t mtime_lo(void)
{
#ifdef configSOC_TIMER_AS_TICK
return *(volatile uint32_t *)TIMERE_LOW_REG;
#else
return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME);
#endif
}
uint32_t mtime_hi(void)
{
#ifdef configSOC_TIMER_AS_TICK
return *(volatile uint32_t *)TIMERE_HIG_REG;
#else
return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4);
#endif
}
uint64_t get_timer_value(void)
{
while (1) {
uint32_t hi = mtime_hi();
uint32_t lo = mtime_lo();
if (hi == mtime_hi())
return ((uint64_t)hi << 32) | lo;
}
}
uint32_t get_timer_freq(void)
{
return TIMER_FREQ;
}
uint64_t get_instret_value(void)
{
while (1) {
uint32_t hi = read_csr(minstreth);
uint32_t lo = read_csr(minstret);
if (hi == read_csr(minstreth))
return ((uint64_t)hi << 32) | lo;
}
}
uint64_t get_cycle_value(void)
{
while (1) {
uint32_t hi = read_csr(mcycleh);
uint32_t lo = read_csr(mcycle);
if (hi == read_csr(mcycleh))
return ((uint64_t)hi << 32) | lo;
}
}
unsigned long interrupt_status_get(void)
{
return read_csr(mstatus) >> 0x3;
}
void interrupt_disable(void)
{
clear_csr(mstatus, MSTATUS_MIE);
}
void interrupt_enable(void)
{
set_csr(mstatus, MSTATUS_MIE);
}
#ifndef CONFIG_N200_REVA
uint32_t __noinline measure_cpu_freq(size_t n)
{
uint32_t start_mtime, delta_mtime;
uint32_t mtime_freq = get_timer_freq();
// Don't start measuruing until we see an mtime tick
uint32_t tmp = mtime_lo();
do {
start_mtime = mtime_lo();
} while (start_mtime == tmp);
uint32_t start_mcycle = read_csr(mcycle);
do {
delta_mtime = mtime_lo() - start_mtime;
} while (delta_mtime < n);
uint32_t delta_mcycle = read_csr(mcycle) - start_mcycle;
return (delta_mcycle / delta_mtime) * mtime_freq +
((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
}
uint32_t get_cpu_freq(void)
{
uint32_t cpu_freq;
// warm up
measure_cpu_freq(1);
// measure for real
cpu_freq = measure_cpu_freq(100);
return cpu_freq;
}
unsigned int xPortIsIsrContext(void)
{
return (read_csr_msubmode & 0xff);
}
#else
unsigned int xPortIsIsrContext(void)
{
return read_csr_msubmode;
}
#endif