5 #include "platform.h"
\r
6 #include "encoding.h"
\r
8 extern int main(int argc, char** argv);
\r
9 extern void trap_entry();
\r
11 static unsigned long mtime_lo(void)
\r
13 return *(volatile unsigned long *)(CLINT_CTRL_ADDR + CLINT_MTIME);
\r
18 static uint32_t mtime_hi(void)
\r
20 return *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 4);
\r
23 uint64_t get_timer_value()
\r
26 uint32_t hi = mtime_hi();
\r
27 uint32_t lo = mtime_lo();
\r
28 if (hi == mtime_hi())
\r
29 return ((uint64_t)hi << 32) | lo;
\r
33 #else /* __riscv32 */
\r
35 uint64_t get_timer_value()
\r
42 unsigned long get_timer_freq()
\r
47 static void use_hfrosc(int div, int trim)
\r
49 // Make sure the HFROSC is running at its default setting
\r
50 PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
\r
51 while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ;
\r
52 PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
\r
55 static void use_pll(int refsel, int bypass, int r, int f, int q)
\r
57 // Ensure that we aren't running off the PLL before we mess with it.
\r
58 if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
\r
59 // Make sure the HFROSC is running at its default setting
\r
63 // Set PLL Source to be HFXOSC if available.
\r
64 uint32_t config_value = 0;
\r
66 config_value |= PLL_REFSEL(refsel);
\r
70 config_value |= PLL_BYPASS(1);
\r
72 PRCI_REG(PRCI_PLLCFG) = config_value;
\r
74 // If we don't have an HFXTAL, this doesn't really matter.
\r
75 // Set our Final output divide to divide-by-1:
\r
76 PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
\r
78 // In case we are executing from QSPI,
\r
79 // (which is quite likely) we need to
\r
80 // set the QSPI clock divider appropriately
\r
81 // before boosting the clock frequency.
\r
84 SPI0_REG(SPI_REG_SCKDIV) = 8;
\r
86 // Set DIV Settings for PLL
\r
87 // Both HFROSC and HFXOSC are modeled as ideal
\r
88 // 16MHz sources (assuming dividers are set properly for
\r
90 // (Legal values of f_REF are 6-48MHz)
\r
92 // Set DIVR to divide-by-2 to get 8MHz frequency
\r
93 // (legal values of f_R are 6-12 MHz)
\r
95 config_value |= PLL_BYPASS(1);
\r
96 config_value |= PLL_R(r);
\r
98 // Set DIVF to get 512Mhz frequncy
\r
99 // There is an implied multiply-by-2, 16Mhz.
\r
100 // So need to write 32-1
\r
101 // (legal values of f_F are 384-768 MHz)
\r
102 config_value |= PLL_F(f);
\r
104 // Set DIVQ to divide-by-2 to get 256 MHz frequency
\r
105 // (legal values of f_Q are 50-400Mhz)
\r
106 config_value |= PLL_Q(q);
\r
108 // Set our Final output divide to divide-by-1:
\r
109 PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
\r
111 PRCI_REG(PRCI_PLLCFG) = config_value;
\r
113 // Un-Bypass the PLL.
\r
114 PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
\r
116 // Wait for PLL Lock
\r
117 // Note that the Lock signal can be glitchy.
\r
118 // Need to wait 100 us
\r
119 // RTC is running at 32kHz.
\r
120 // So wait 4 ticks of RTC.
\r
121 uint32_t now = mtime_lo();
\r
122 while (mtime_lo() - now < 4) ;
\r
124 // Now it is safe to check for PLL Lock
\r
125 while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) ;
\r
128 // Switch over to PLL Clock source
\r
129 PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
\r
132 static void use_default_clocks()
\r
134 // Turn off the LFROSC
\r
135 AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
\r
141 static unsigned long __attribute__((noinline)) measure_cpu_freq(size_t n)
\r
143 unsigned long start_mtime, delta_mtime;
\r
144 unsigned long mtime_freq = get_timer_freq();
\r
146 // Don't start measuruing until we see an mtime tick
\r
147 unsigned long tmp = mtime_lo();
\r
149 start_mtime = mtime_lo();
\r
150 } while (start_mtime == tmp);
\r
152 unsigned long start_mcycle = read_csr(mcycle);
\r
155 delta_mtime = mtime_lo() - start_mtime;
\r
156 } while (delta_mtime < n);
\r
158 unsigned long delta_mcycle = read_csr(mcycle) - start_mcycle;
\r
160 return (delta_mcycle / delta_mtime) * mtime_freq
\r
161 + ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
\r
164 unsigned long get_cpu_freq()
\r
166 static uint32_t cpu_freq;
\r
170 measure_cpu_freq(1);
\r
171 // measure for real
\r
172 cpu_freq = measure_cpu_freq(10);
\r
178 static void uart_init(size_t baud_rate)
\r
180 GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
\r
181 GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
\r
182 UART0_REG(UART_REG_DIV) = get_cpu_freq() / baud_rate - 1;
\r
183 UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
\r
189 extern void handle_m_ext_interrupt();
\r
193 extern void handle_m_time_interrupt();
\r
196 uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
\r
200 // External Machine-Level interrupt from PLIC
\r
201 } else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) {
\r
202 handle_m_ext_interrupt();
\r
205 // External Machine-Level interrupt from PLIC
\r
206 } else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)){
\r
207 handle_m_time_interrupt();
\r
211 write(1, "trap\n", 5);
\r
221 use_default_clocks();
\r
222 use_pll(0, 0, 1, 31, 1);
\r
225 printf("core freq at %d Hz\n", get_cpu_freq());
\r
227 write_csr(mtvec, &trap_entry);
\r
228 if (read_csr(misa) & (1 << ('F' - 'A'))) { // if F extension is present
\r
229 write_csr(mstatus, MSTATUS_FS); // allow FPU instructions without trapping
\r
230 write_csr(fcsr, 0); // initialize rounding mode, undefined at reset
\r