Teensy 4.1 core updated for C++20
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

177 lines
6.0KB

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