Teensy 4.1 core updated for C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.9KB

  1. #include <stdint.h>
  2. #include "imxrt.h"
  3. #include "wiring.h"
  4. #include "debug/printf.h"
  5. volatile uint32_t F_CPU_ACTUAL = 396000000;
  6. volatile uint32_t F_BUS_ACTUAL = 132000000;
  7. // Define these to increase the voltage when attempting overclocking
  8. // The frequency step is how quickly to increase voltage per frequency
  9. // The datasheet says 1300 is the absolute maximum voltage. The hardware
  10. // can actually create up to 1575, but going over 1300 risks damage!
  11. #define OVERCLOCK_STEPSIZE 28000000
  12. #define OVERCLOCK_MAX_VOLT 1300
  13. //#define OVERCLOCK_MAX_VOLT 1575 // Danger Will Robinson!
  14. uint32_t set_arm_clock(uint32_t frequency);
  15. // stuff needing wait handshake:
  16. // CCM_CACRR ARM_PODF
  17. // CCM_CBCDR PERIPH_CLK_SEL
  18. // CCM_CBCMR PERIPH2_CLK_SEL
  19. // CCM_CBCDR AHB_PODF
  20. // CCM_CBCDR SEMC_PODF
  21. uint32_t set_arm_clock(uint32_t frequency)
  22. {
  23. uint32_t cbcdr = CCM_CBCDR; // pg 1021
  24. uint32_t cbcmr = CCM_CBCMR; // pg 1023
  25. uint32_t dcdc = DCDC_REG3;
  26. // compute required voltage
  27. uint32_t voltage = 1150; // default = 1.15V
  28. if (frequency > 528000000) {
  29. voltage = 1250; // 1.25V
  30. #if defined(OVERCLOCK_STEPSIZE) && defined(OVERCLOCK_MAX_VOLT)
  31. if (frequency > 600000000) {
  32. voltage += ((frequency - 600000000) / OVERCLOCK_STEPSIZE) * 25;
  33. if (voltage > OVERCLOCK_MAX_VOLT) voltage = OVERCLOCK_MAX_VOLT;
  34. }
  35. #endif
  36. } else if (frequency <= 24) {
  37. voltage = 950; // 0.95
  38. }
  39. // if voltage needs to increase, do it before switch clock speed
  40. CCM_CCGR6 |= CCM_CCGR6_DCDC(CCM_CCGR_ON);
  41. if ((dcdc & DCDC_REG3_TRG_MASK) < DCDC_REG3_TRG((voltage - 800) / 25)) {
  42. printf("Increasing voltage to %u mV\n", voltage);
  43. dcdc &= ~DCDC_REG3_TRG_MASK;
  44. dcdc |= DCDC_REG3_TRG((voltage - 800) / 25);
  45. DCDC_REG3 = dcdc;
  46. while (!(DCDC_REG0 & DCDC_REG0_STS_DC_OK)) ; // wait voltage settling
  47. }
  48. if (!(cbcdr & CCM_CBCDR_PERIPH_CLK_SEL)) {
  49. printf("need to switch to alternate clock during reconfigure of ARM PLL\n");
  50. const uint32_t need1s = CCM_ANALOG_PLL_USB1_ENABLE | CCM_ANALOG_PLL_USB1_POWER |
  51. CCM_ANALOG_PLL_USB1_LOCK | CCM_ANALOG_PLL_USB1_EN_USB_CLKS;
  52. uint32_t sel, div;
  53. if ((CCM_ANALOG_PLL_USB1 & need1s) == need1s) {
  54. printf("USB PLL is running, so we can use 120 MHz\n");
  55. sel = 0;
  56. div = 3; // divide down to 120 MHz, so IPG is ok even if IPG_PODF=0
  57. } else {
  58. printf("USB PLL is off, use 24 MHz crystal\n");
  59. sel = 1;
  60. div = 0;
  61. }
  62. if ((cbcdr & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) != CCM_CBCDR_PERIPH_CLK2_PODF(div)) {
  63. // PERIPH_CLK2 divider needs to be changed
  64. cbcdr &= ~CCM_CBCDR_PERIPH_CLK2_PODF_MASK;
  65. cbcdr |= CCM_CBCDR_PERIPH_CLK2_PODF(div);
  66. CCM_CBCDR = cbcdr;
  67. }
  68. if ((cbcmr & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) != CCM_CBCMR_PERIPH_CLK2_SEL(sel)) {
  69. // PERIPH_CLK2 source select needs to be changed
  70. cbcmr &= ~CCM_CBCMR_PERIPH_CLK2_SEL_MASK;
  71. cbcmr |= CCM_CBCMR_PERIPH_CLK2_SEL(sel);
  72. CCM_CBCMR = cbcmr;
  73. while (CCM_CDHIPR & CCM_CDHIPR_PERIPH2_CLK_SEL_BUSY) ; // wait
  74. }
  75. // switch over to PERIPH_CLK2
  76. cbcdr |= CCM_CBCDR_PERIPH_CLK_SEL;
  77. CCM_CBCDR = cbcdr;
  78. while (CCM_CDHIPR & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) ; // wait
  79. } else {
  80. printf("already running from PERIPH_CLK2, safe to mess with ARM PLL\n");
  81. }
  82. // TODO: check if PLL2 running, can 352, 396 or 528 can work? (no need for ARM PLL)
  83. // DIV_SELECT: 54-108 = official range 648 to 1296 in 12 MHz steps
  84. uint32_t div_arm = 1;
  85. uint32_t div_ahb = 1;
  86. while (frequency * div_arm * div_ahb < 648000000) {
  87. if (div_arm < 8) {
  88. div_arm = div_arm + 1;
  89. } else {
  90. if (div_ahb < 5) {
  91. div_ahb = div_ahb + 1;
  92. div_arm = 1;
  93. } else {
  94. break;
  95. }
  96. }
  97. }
  98. uint32_t mult = (frequency * div_arm * div_ahb + 6000000) / 12000000;
  99. if (mult > 108) mult = 108;
  100. if (mult < 54) mult = 54;
  101. printf("Freq: 12 MHz * %u / %u / %u\n", mult, div_arm, div_ahb);
  102. frequency = mult * 12000000 / div_arm / div_ahb;
  103. printf("ARM PLL=%x\n", CCM_ANALOG_PLL_ARM);
  104. const uint32_t arm_pll_mask = CCM_ANALOG_PLL_ARM_LOCK | CCM_ANALOG_PLL_ARM_BYPASS |
  105. CCM_ANALOG_PLL_ARM_ENABLE | CCM_ANALOG_PLL_ARM_POWERDOWN |
  106. CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK;
  107. if ((CCM_ANALOG_PLL_ARM & arm_pll_mask) != (CCM_ANALOG_PLL_ARM_LOCK
  108. | CCM_ANALOG_PLL_ARM_ENABLE | CCM_ANALOG_PLL_ARM_DIV_SELECT(mult))) {
  109. printf("ARM PLL needs reconfigure\n");
  110. CCM_ANALOG_PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN;
  111. // TODO: delay needed?
  112. CCM_ANALOG_PLL_ARM = CCM_ANALOG_PLL_ARM_ENABLE
  113. | CCM_ANALOG_PLL_ARM_DIV_SELECT(mult);
  114. while (!(CCM_ANALOG_PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK)) ; // wait for lock
  115. printf("ARM PLL=%x\n", CCM_ANALOG_PLL_ARM);
  116. } else {
  117. printf("ARM PLL already running at required frequency\n");
  118. }
  119. if ((CCM_CACRR & CCM_CACRR_ARM_PODF_MASK) != (div_arm - 1)) {
  120. CCM_CACRR = CCM_CACRR_ARM_PODF(div_arm - 1);
  121. while (CCM_CDHIPR & CCM_CDHIPR_ARM_PODF_BUSY) ; // wait
  122. }
  123. if ((cbcdr & CCM_CBCDR_AHB_PODF_MASK) != CCM_CBCDR_AHB_PODF(div_ahb - 1)) {
  124. cbcdr &= ~CCM_CBCDR_AHB_PODF_MASK;
  125. cbcdr |= CCM_CBCDR_AHB_PODF(div_ahb - 1);
  126. CCM_CBCDR = cbcdr;
  127. while (CCM_CDHIPR & CCM_CDHIPR_AHB_PODF_BUSY); // wait
  128. }
  129. uint32_t div_ipg = (frequency + 149999999) / 150000000;
  130. if (div_ipg > 4) div_ipg = 4;
  131. if ((cbcdr & CCM_CBCDR_IPG_PODF_MASK) != (CCM_CBCDR_IPG_PODF(div_ipg - 1))) {
  132. cbcdr &= ~CCM_CBCDR_IPG_PODF_MASK;
  133. cbcdr |= CCM_CBCDR_IPG_PODF(div_ipg - 1);
  134. // TODO: how to safely change IPG_PODF ??
  135. CCM_CBCDR = cbcdr;
  136. }
  137. cbcdr &= ~CCM_CBCDR_PERIPH_CLK_SEL;
  138. CCM_CBCDR = cbcdr;
  139. while (CCM_CDHIPR & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) ; // wait
  140. F_CPU_ACTUAL = frequency;
  141. F_BUS_ACTUAL = frequency / div_ipg;
  142. printf("New Frequency: ARM=%u, IPG=%u\n", frequency, frequency / div_ipg);
  143. // if voltage needs to decrease, do it after switch clock speed
  144. if ((dcdc & DCDC_REG3_TRG_MASK) > DCDC_REG3_TRG((voltage - 800) / 25)) {
  145. printf("Decreasing voltage to %u mV\n", voltage);
  146. dcdc &= ~DCDC_REG3_TRG_MASK;
  147. dcdc |= DCDC_REG3_TRG((voltage - 800) / 25);
  148. DCDC_REG3 = dcdc;
  149. while (!(DCDC_REG0 & DCDC_REG0_STS_DC_OK)) ; // wait voltage settling
  150. }
  151. return frequency;
  152. }