123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- #include <stdint.h>
- #include <stdio.h>
- #include <unistd.h>
- #include "platform.h"
- #include "encoding.h"
- extern int main(int argc, char** argv);
- extern void trap_entry();
- static unsigned long mtime_lo(void)
- {
- return *(volatile unsigned long *)(CLINT_CTRL_ADDR + CLINT_MTIME);
- }
- #ifdef __riscv32
- static uint32_t mtime_hi(void)
- {
- return *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 4);
- }
- uint64_t get_timer_value()
- {
- while (1) {
- uint32_t hi = mtime_hi();
- uint32_t lo = mtime_lo();
- if (hi == mtime_hi())
- return ((uint64_t)hi << 32) | lo;
- }
- }
- #else /* __riscv32 */
- uint64_t get_timer_value()
- {
- return mtime_lo();
- }
- #endif
- unsigned long get_timer_freq()
- {
- return 32768;
- }
- static void use_hfrosc(int div, int trim)
- {
- // Make sure the HFROSC is running at its default setting
- PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
- while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ;
- PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
- }
- static void use_pll(int refsel, int bypass, int r, int f, int q)
- {
- // Ensure that we aren't running off the PLL before we mess with it.
- if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
- // Make sure the HFROSC is running at its default setting
- use_hfrosc(4, 16);
- }
- // Set PLL Source to be HFXOSC if available.
- uint32_t config_value = 0;
- config_value |= PLL_REFSEL(refsel);
- if (bypass) {
- // Bypass
- config_value |= PLL_BYPASS(1);
- PRCI_REG(PRCI_PLLCFG) = config_value;
- // If we don't have an HFXTAL, this doesn't really matter.
- // Set our Final output divide to divide-by-1:
- PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
- } else {
- // In case we are executing from QSPI,
- // (which is quite likely) we need to
- // set the QSPI clock divider appropriately
- // before boosting the clock frequency.
- // Div = f_sck/2
- SPI0_REG(SPI_REG_SCKDIV) = 8;
- // Set DIV Settings for PLL
- // Both HFROSC and HFXOSC are modeled as ideal
- // 16MHz sources (assuming dividers are set properly for
- // HFROSC).
- // (Legal values of f_REF are 6-48MHz)
- // Set DIVR to divide-by-2 to get 8MHz frequency
- // (legal values of f_R are 6-12 MHz)
- config_value |= PLL_BYPASS(1);
- config_value |= PLL_R(r);
- // Set DIVF to get 512Mhz frequncy
- // There is an implied multiply-by-2, 16Mhz.
- // So need to write 32-1
- // (legal values of f_F are 384-768 MHz)
- config_value |= PLL_F(f);
- // Set DIVQ to divide-by-2 to get 256 MHz frequency
- // (legal values of f_Q are 50-400Mhz)
- config_value |= PLL_Q(q);
- // Set our Final output divide to divide-by-1:
- PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
- PRCI_REG(PRCI_PLLCFG) = config_value;
- // Un-Bypass the PLL.
- PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
- // Wait for PLL Lock
- // Note that the Lock signal can be glitchy.
- // Need to wait 100 us
- // RTC is running at 32kHz.
- // So wait 4 ticks of RTC.
- uint32_t now = mtime_lo();
- while (mtime_lo() - now < 4) ;
- // Now it is safe to check for PLL Lock
- while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) ;
- }
- // Switch over to PLL Clock source
- PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
- }
- static void use_default_clocks()
- {
- // Turn off the LFROSC
- AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
- // Use HFROSC
- use_hfrosc(4, 16);
- }
- static unsigned long __attribute__((noinline)) measure_cpu_freq(size_t n)
- {
- unsigned long start_mtime, delta_mtime;
- unsigned long mtime_freq = get_timer_freq();
- // Don't start measuruing until we see an mtime tick
- unsigned long tmp = mtime_lo();
- do {
- start_mtime = mtime_lo();
- } while (start_mtime == tmp);
- unsigned long start_mcycle = read_csr(mcycle);
- do {
- delta_mtime = mtime_lo() - start_mtime;
- } while (delta_mtime < n);
- unsigned long delta_mcycle = read_csr(mcycle) - start_mcycle;
- return (delta_mcycle / delta_mtime) * mtime_freq
- + ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
- }
- unsigned long get_cpu_freq()
- {
- static uint32_t cpu_freq;
- if (!cpu_freq) {
- // warm up I$
- measure_cpu_freq(1);
- // measure for real
- cpu_freq = measure_cpu_freq(10);
- }
- return cpu_freq;
- }
- #ifdef USE_PLIC
- extern void handle_m_ext_interrupt();
- #endif
- #ifdef USE_M_TIME
- extern void handle_m_time_interrupt();
- #endif
- void _init()
- {
-
- #ifndef NO_INIT
- use_default_clocks();
- use_pll(0, 0, 1, 31, 1);
- write_csr(mtvec, &trap_entry);
- if (read_csr(misa) & (1 << ('F' - 'A'))) { // if F extension is present
- write_csr(mstatus, MSTATUS_FS); // allow FPU instructions without trapping
- write_csr(fcsr, 0); // initialize rounding mode, undefined at reset
- }
- #endif
-
- }
- void _fini()
- {
- }
|