init.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include "platform.h"
  5. #include "encoding.h"
  6. extern int main(int argc, char** argv);
  7. extern void trap_entry();
  8. static unsigned long mtime_lo(void)
  9. {
  10. return *(volatile unsigned long *)(CLINT_CTRL_ADDR + CLINT_MTIME);
  11. }
  12. #ifdef __riscv32
  13. static uint32_t mtime_hi(void)
  14. {
  15. return *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 4);
  16. }
  17. uint64_t get_timer_value()
  18. {
  19. while (1) {
  20. uint32_t hi = mtime_hi();
  21. uint32_t lo = mtime_lo();
  22. if (hi == mtime_hi())
  23. return ((uint64_t)hi << 32) | lo;
  24. }
  25. }
  26. #else /* __riscv32 */
  27. uint64_t get_timer_value()
  28. {
  29. return mtime_lo();
  30. }
  31. #endif
  32. unsigned long get_timer_freq()
  33. {
  34. return 32768;
  35. }
  36. static void use_hfrosc(int div, int trim)
  37. {
  38. // Make sure the HFROSC is running at its default setting
  39. PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
  40. while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ;
  41. PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
  42. }
  43. static void use_pll(int refsel, int bypass, int r, int f, int q)
  44. {
  45. // Ensure that we aren't running off the PLL before we mess with it.
  46. if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
  47. // Make sure the HFROSC is running at its default setting
  48. use_hfrosc(4, 16);
  49. }
  50. // Set PLL Source to be HFXOSC if available.
  51. uint32_t config_value = 0;
  52. config_value |= PLL_REFSEL(refsel);
  53. if (bypass) {
  54. // Bypass
  55. config_value |= PLL_BYPASS(1);
  56. PRCI_REG(PRCI_PLLCFG) = config_value;
  57. // If we don't have an HFXTAL, this doesn't really matter.
  58. // Set our Final output divide to divide-by-1:
  59. PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
  60. } else {
  61. // In case we are executing from QSPI,
  62. // (which is quite likely) we need to
  63. // set the QSPI clock divider appropriately
  64. // before boosting the clock frequency.
  65. // Div = f_sck/2
  66. SPI0_REG(SPI_REG_SCKDIV) = 8;
  67. // Set DIV Settings for PLL
  68. // Both HFROSC and HFXOSC are modeled as ideal
  69. // 16MHz sources (assuming dividers are set properly for
  70. // HFROSC).
  71. // (Legal values of f_REF are 6-48MHz)
  72. // Set DIVR to divide-by-2 to get 8MHz frequency
  73. // (legal values of f_R are 6-12 MHz)
  74. config_value |= PLL_BYPASS(1);
  75. config_value |= PLL_R(r);
  76. // Set DIVF to get 512Mhz frequncy
  77. // There is an implied multiply-by-2, 16Mhz.
  78. // So need to write 32-1
  79. // (legal values of f_F are 384-768 MHz)
  80. config_value |= PLL_F(f);
  81. // Set DIVQ to divide-by-2 to get 256 MHz frequency
  82. // (legal values of f_Q are 50-400Mhz)
  83. config_value |= PLL_Q(q);
  84. // Set our Final output divide to divide-by-1:
  85. PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
  86. PRCI_REG(PRCI_PLLCFG) = config_value;
  87. // Un-Bypass the PLL.
  88. PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
  89. // Wait for PLL Lock
  90. // Note that the Lock signal can be glitchy.
  91. // Need to wait 100 us
  92. // RTC is running at 32kHz.
  93. // So wait 4 ticks of RTC.
  94. uint32_t now = mtime_lo();
  95. while (mtime_lo() - now < 4) ;
  96. // Now it is safe to check for PLL Lock
  97. while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) ;
  98. }
  99. // Switch over to PLL Clock source
  100. PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
  101. }
  102. static void use_default_clocks()
  103. {
  104. // Turn off the LFROSC
  105. AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
  106. // Use HFROSC
  107. use_hfrosc(4, 16);
  108. }
  109. static unsigned long __attribute__((noinline)) measure_cpu_freq(size_t n)
  110. {
  111. unsigned long start_mtime, delta_mtime;
  112. unsigned long mtime_freq = get_timer_freq();
  113. // Don't start measuruing until we see an mtime tick
  114. unsigned long tmp = mtime_lo();
  115. do {
  116. start_mtime = mtime_lo();
  117. } while (start_mtime == tmp);
  118. unsigned long start_mcycle = read_csr(mcycle);
  119. do {
  120. delta_mtime = mtime_lo() - start_mtime;
  121. } while (delta_mtime < n);
  122. unsigned long delta_mcycle = read_csr(mcycle) - start_mcycle;
  123. return (delta_mcycle / delta_mtime) * mtime_freq
  124. + ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
  125. }
  126. unsigned long get_cpu_freq()
  127. {
  128. static uint32_t cpu_freq;
  129. if (!cpu_freq) {
  130. // warm up I$
  131. measure_cpu_freq(1);
  132. // measure for real
  133. cpu_freq = measure_cpu_freq(10);
  134. }
  135. return cpu_freq;
  136. }
  137. #ifdef USE_PLIC
  138. extern void handle_m_ext_interrupt();
  139. #endif
  140. #ifdef USE_M_TIME
  141. extern void handle_m_time_interrupt();
  142. #endif
  143. void _init()
  144. {
  145. #ifndef NO_INIT
  146. use_default_clocks();
  147. use_pll(0, 0, 1, 31, 1);
  148. write_csr(mtvec, &trap_entry);
  149. if (read_csr(misa) & (1 << ('F' - 'A'))) { // if F extension is present
  150. write_csr(mstatus, MSTATUS_FS); // allow FPU instructions without trapping
  151. write_csr(fcsr, 0); // initialize rounding mode, undefined at reset
  152. }
  153. #endif
  154. }
  155. void _fini()
  156. {
  157. }