github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_mimxrt1062_clock.go (about)

     1  //go:build mimxrt1062
     2  
     3  package runtime
     4  
     5  import (
     6  	"device/nxp"
     7  )
     8  
     9  // Core clock frequencies (Hz)
    10  const (
    11  	CORE_FREQ = 600000000 // 600 MHz
    12  	OSC_FREQ  = 24000000  //  24 MHz
    13  )
    14  
    15  // Note from Teensyduino (cores/teensy4/startup.c):
    16  //
    17  // |  ARM SysTick is used for most Ardiuno timing functions, delay(), millis(),
    18  // |  micros().  SysTick can run from either the ARM core clock, or from an
    19  // |  "external" clock.  NXP documents it as "24 MHz XTALOSC can be the external
    20  // |  clock source of SYSTICK" (RT1052 ref manual, rev 1, page 411).  However,
    21  // |  NXP actually hid an undocumented divide-by-240 circuit in the hardware, so
    22  // |  the external clock is really 100 kHz.  We use this clock rather than the
    23  // |  ARM clock, to allow SysTick to maintain correct timing even when we change
    24  // |  the ARM clock to run at different speeds.
    25  const SYSTICK_FREQ = 100000 // 100 kHz
    26  
    27  var (
    28  	ArmPllConfig = nxp.ClockConfigArmPll{
    29  		LoopDivider: 100, // PLL loop divider, Fout=Fin*50
    30  		Src:         0,   // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
    31  	}
    32  	SysPllConfig = nxp.ClockConfigSysPll{
    33  		LoopDivider: 1, // PLL loop divider, Fout=Fin*(20+LOOP*2+NUMER/DENOM)
    34  		Numerator:   0, // 30-bit NUMER of fractional loop divider
    35  		Denominator: 1, // 30-bit DENOM of fractional loop divider
    36  		Src:         0, // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
    37  	}
    38  	Usb1PllConfig = nxp.ClockConfigUsbPll{
    39  		Instance:    1, // USB PLL instance
    40  		LoopDivider: 0, // PLL loop divider, Fout=Fin*20
    41  		Src:         0, // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
    42  	}
    43  	Usb2PllConfig = nxp.ClockConfigUsbPll{
    44  		Instance:    2, // USB PLL instance
    45  		LoopDivider: 0, // PLL loop divider, Fout=Fin*20
    46  		Src:         0, // bypass clock source, 0=OSC24M, 1=CLK1_P & CLK1_N
    47  	}
    48  )
    49  
    50  // initClocks configures the core, buses, and all peripherals' clock source mux
    51  // and dividers for runtime. The clock gates for individual peripherals are all
    52  // disabled prior to configuration and must be enabled afterwards using one of
    53  // these `enable*Clocks()` functions or the respective peripheral clocks'
    54  // `Enable()` method from the "device/nxp" package.
    55  func initClocks() {
    56  	// disable low-power mode so that __WFI doesn't lock up at runtime.
    57  	// see: Using the MIMXRT1060/4-EVK with MCUXpresso IDE v10.3.x (v1.0.2,
    58  	// 2019MAR01), chapter 14
    59  	nxp.ClockModeRun.Set()
    60  
    61  	// enable and use 1MHz clock output
    62  	nxp.XTALOSC24M.OSC_CONFIG2.SetBits(nxp.XTALOSC24M_OSC_CONFIG2_ENABLE_1M_Msk)
    63  	nxp.XTALOSC24M.OSC_CONFIG2.ClearBits(nxp.XTALOSC24M_OSC_CONFIG2_MUX_1M_Msk)
    64  
    65  	// initialize external 24 MHz clock
    66  	nxp.CCM_ANALOG.MISC0_CLR.Set(nxp.CCM_ANALOG_MISC0_XTAL_24M_PWD_Msk) // power
    67  	for !nxp.XTALOSC24M.LOWPWR_CTRL.HasBits(nxp.XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_Msk) {
    68  	}
    69  	nxp.CCM_ANALOG.MISC0_SET.Set(nxp.CCM_ANALOG_MISC0_OSC_XTALOK_EN_Msk) // detect freq
    70  	for !nxp.CCM_ANALOG.MISC0.HasBits(nxp.CCM_ANALOG_MISC0_OSC_XTALOK_Msk) {
    71  	}
    72  	nxp.CCM_ANALOG.MISC0_CLR.Set(nxp.CCM_ANALOG_MISC0_OSC_XTALOK_EN_Msk)
    73  
    74  	// initialize internal RC OSC 24 MHz, and switch clock source to external OSC
    75  	nxp.XTALOSC24M.LOWPWR_CTRL.SetBits(nxp.XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_Msk)
    76  	nxp.XTALOSC24M.LOWPWR_CTRL_CLR.Set(nxp.XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_Msk)
    77  
    78  	// set oscillator ready counter value
    79  	nxp.CCM.CCR.Set((nxp.CCM.CCR.Get() & ^uint32(nxp.CCM_CCR_OSCNT_Msk)) |
    80  		((127 << nxp.CCM_CCR_OSCNT_Pos) & nxp.CCM_CCR_OSCNT_Msk))
    81  
    82  	// set PERIPH2_CLK and PERIPH to provide stable clock before PLLs initialed
    83  	nxp.MuxIpPeriphClk2.Mux(1) // PERIPH_CLK2 select OSC24M
    84  	nxp.MuxIpPeriph.Mux(1)     // PERIPH select PERIPH_CLK2
    85  
    86  	// set VDD_SOC to 1.275V, necessary to config AHB to 600 MHz
    87  	nxp.DCDC.REG3.Set((nxp.DCDC.REG3.Get() & ^uint32(nxp.DCDC_REG3_TRG_Msk)) |
    88  		((13 << nxp.DCDC_REG3_TRG_Pos) & nxp.DCDC_REG3_TRG_Msk))
    89  
    90  	// wait until DCDC_STS_DC_OK bit is asserted
    91  	for !nxp.DCDC.REG0.HasBits(nxp.DCDC_REG0_STS_DC_OK_Msk) {
    92  	}
    93  
    94  	nxp.DivIpAhb.Div(0) // divide AHB_PODF (DIV1)
    95  
    96  	nxp.ClockIpAdc1.Enable(false) // disable ADC
    97  	nxp.ClockIpAdc2.Enable(false) //
    98  
    99  	nxp.ClockIpXbar1.Enable(false) //  disable XBAR
   100  	nxp.ClockIpXbar2.Enable(false) //
   101  	nxp.ClockIpXbar3.Enable(false) //
   102  
   103  	nxp.DivIpIpg.Div(3)        // divide IPG_PODF (DIV4)
   104  	nxp.DivIpArm.Div(1)        // divide ARM_PODF (DIV2)
   105  	nxp.DivIpPeriphClk2.Div(0) // divide PERIPH_CLK2_PODF (DIV1)
   106  
   107  	nxp.ClockIpGpt1.Enable(false)  // disable GPT/PIT
   108  	nxp.ClockIpGpt1S.Enable(false) //
   109  	nxp.ClockIpGpt2.Enable(false)  //
   110  	nxp.ClockIpGpt2S.Enable(false) //
   111  	nxp.ClockIpPit.Enable(false)   //
   112  
   113  	nxp.DivIpPerclk.Div(0) // divide PERCLK_PODF (DIV1)
   114  
   115  	nxp.ClockIpUsdhc1.Enable(false) // disable USDHC1
   116  	nxp.DivIpUsdhc1.Div(1)          // divide USDHC1_PODF (DIV2)
   117  	nxp.MuxIpUsdhc1.Mux(1)          // USDHC1 select PLL2_PFD0
   118  	nxp.ClockIpUsdhc2.Enable(false) // disable USDHC2
   119  	nxp.DivIpUsdhc2.Div(1)          // divide USDHC2_PODF (DIV2)
   120  	nxp.MuxIpUsdhc2.Mux(1)          // USDHC2 select PLL2_PFD0
   121  
   122  	nxp.ClockIpSemc.Enable(false) // disable SEMC
   123  	nxp.DivIpSemc.Div(1)          // divide SEMC_PODF (DIV2)
   124  	nxp.MuxIpSemcAlt.Mux(0)       // SEMC_ALT select PLL2_PFD2
   125  	nxp.MuxIpSemc.Mux(1)          // SEMC select SEMC_ALT
   126  
   127  	if false {
   128  		// TODO: external flash is on this bus, configured via DCD block
   129  		nxp.ClockIpFlexSpi.Enable(false) // disable FLEXSPI
   130  		nxp.DivIpFlexSpi.Div(0)          // divide FLEXSPI_PODF (DIV1)
   131  		nxp.MuxIpFlexSpi.Mux(2)          // FLEXSPI select PLL2_PFD2
   132  	}
   133  	nxp.ClockIpFlexSpi2.Enable(false) // disable FLEXSPI2
   134  	nxp.DivIpFlexSpi2.Div(0)          // divide FLEXSPI2_PODF (DIV1)
   135  	nxp.MuxIpFlexSpi2.Mux(0)          // FLEXSPI2 select PLL2_PFD2
   136  
   137  	nxp.ClockIpCsi.Enable(false) // disable CSI
   138  	nxp.DivIpCsi.Div(1)          // divide CSI_PODF (DIV2)
   139  	nxp.MuxIpCsi.Mux(0)          // CSI select OSC24M
   140  
   141  	nxp.ClockIpLpspi1.Enable(false) // disable LPSPI
   142  	nxp.ClockIpLpspi2.Enable(false) //
   143  	nxp.ClockIpLpspi3.Enable(false) //
   144  	nxp.ClockIpLpspi4.Enable(false) //
   145  	nxp.DivIpLpspi.Div(3)           // divide LPSPI_PODF (DIV4)
   146  	nxp.MuxIpLpspi.Mux(2)           // LPSPI select PLL2
   147  
   148  	nxp.ClockIpTrace.Enable(false) // disable TRACE
   149  	nxp.DivIpTrace.Div(3)          // divide TRACE_PODF (DIV4)
   150  	nxp.MuxIpTrace.Mux(0)          // TRACE select PLL2_MAIN
   151  
   152  	nxp.ClockIpSai1.Enable(false) // disable SAI1
   153  	nxp.DivIpSai1Pre.Div(3)       // divide SAI1_CLK_PRED (DIV4)
   154  	nxp.DivIpSai1.Div(1)          // divide SAI1_CLK_PODF (DIV2)
   155  	nxp.MuxIpSai1.Mux(0)          // SAI1 select PLL3_PFD2
   156  	nxp.ClockIpSai2.Enable(false) // disable SAI2
   157  	nxp.DivIpSai2Pre.Div(3)       // divide SAI2_CLK_PRED (DIV4)
   158  	nxp.DivIpSai2.Div(1)          // divide SAI2_CLK_PODF (DIV2)
   159  	nxp.MuxIpSai2.Mux(0)          // SAI2 select PLL3_PFD2
   160  	nxp.ClockIpSai3.Enable(false) // disable SAI3
   161  	nxp.DivIpSai3Pre.Div(3)       // divide SAI3_CLK_PRED (DIV4)
   162  	nxp.DivIpSai3.Div(1)          // divide SAI3_CLK_PODF (DIV2)
   163  	nxp.MuxIpSai3.Mux(0)          // SAI3 select PLL3_PFD2
   164  
   165  	nxp.ClockIpLpi2c1.Enable(false) // disable LPI2C
   166  	nxp.ClockIpLpi2c2.Enable(false) //
   167  	nxp.ClockIpLpi2c3.Enable(false) //
   168  	nxp.ClockIpLpi2c4.Enable(false) //
   169  	nxp.DivIpLpi2c.Div(0)           // divide LPI2C_CLK_PODF (DIV1)
   170  	nxp.MuxIpLpi2c.Mux(1)           // LPI2C select OSC
   171  
   172  	nxp.ClockIpCan1.Enable(false)  // disable CAN
   173  	nxp.ClockIpCan2.Enable(false)  //
   174  	nxp.ClockIpCan3.Enable(false)  //
   175  	nxp.ClockIpCan1S.Enable(false) //
   176  	nxp.ClockIpCan2S.Enable(false) //
   177  	nxp.ClockIpCan3S.Enable(false) //
   178  	nxp.DivIpCan.Div(1)            // divide CAN_CLK_PODF (DIV2)
   179  	nxp.MuxIpCan.Mux(2)            // CAN select PLL3_SW_80M
   180  
   181  	nxp.ClockIpLpuart1.Enable(false) // disable UART
   182  	nxp.ClockIpLpuart2.Enable(false) //
   183  	nxp.ClockIpLpuart3.Enable(false) //
   184  	nxp.ClockIpLpuart4.Enable(false) //
   185  	nxp.ClockIpLpuart5.Enable(false) //
   186  	nxp.ClockIpLpuart6.Enable(false) //
   187  	nxp.ClockIpLpuart7.Enable(false) //
   188  	nxp.ClockIpLpuart8.Enable(false) //
   189  	nxp.DivIpUart.Div(0)             // divide UART_CLK_PODF (DIV1)
   190  	nxp.MuxIpUart.Mux(1)             // UART select OSC
   191  
   192  	nxp.ClockIpLcdPixel.Enable(false) // disable LCDIF
   193  	nxp.DivIpLcdifPre.Div(1)          // divide LCDIF_PRED (DIV2)
   194  	nxp.DivIpLcdif.Div(3)             // divide LCDIF_CLK_PODF (DIV4)
   195  	nxp.MuxIpLcdifPre.Mux(5)          // LCDIF_PRE select PLL3_PFD1
   196  
   197  	nxp.ClockIpSpdif.Enable(false) // disable SPDIF
   198  	nxp.DivIpSpdif0Pre.Div(1)      // divide SPDIF0_CLK_PRED (DIV2)
   199  	nxp.DivIpSpdif0.Div(7)         // divide SPDIF0_CLK_PODF (DIV8)
   200  	nxp.MuxIpSpdif.Mux(3)          // SPDIF select PLL3_SW
   201  
   202  	nxp.ClockIpFlexio1.Enable(false) // disable FLEXIO1
   203  	nxp.DivIpFlexio1Pre.Div(1)       // divide FLEXIO1_CLK_PRED (DIV2)
   204  	nxp.DivIpFlexio1.Div(7)          // divide FLEXIO1_CLK_PODF (DIV8)
   205  	nxp.MuxIpFlexio1.Mux(3)          // FLEXIO1 select PLL3_SW
   206  	nxp.ClockIpFlexio2.Enable(false) // disable FLEXIO2
   207  	nxp.DivIpFlexio2Pre.Div(1)       // divide FLEXIO2_CLK_PRED (DIV2)
   208  	nxp.DivIpFlexio2.Div(7)          // divide FLEXIO2_CLK_PODF (DIV8)
   209  	nxp.MuxIpFlexio2.Mux(3)          // FLEXIO2 select PLL3_SW
   210  
   211  	nxp.MuxIpPll3Sw.Mux(0) // PLL3_SW select PLL3_MAIN
   212  
   213  	ArmPllConfig.Configure() // init ARM PLL
   214  	// SYS PLL (PLL2) @ 528 MHz
   215  	//   PFD0 = 396    MHz -> USDHC1/USDHC2(DIV2)=198 MHz
   216  	//   PFD1 = 594    MHz -> (currently unused)
   217  	//   PFD2 = 327.72 MHz -> SEMC(DIV2)=163.86 MHz, FlexSPI/FlexSPI2=327.72 MHz
   218  	//   PFD3 = 454.73 MHz -> (currently unused)
   219  	SysPllConfig.Configure(24, 16, 29, 16) // init SYS PLL and PFDs
   220  
   221  	// USB1 PLL (PLL3) @ 480 MHz
   222  	//   PFD0 -> (currently unused)
   223  	//   PFD1 -> (currently unused)
   224  	//   PFD2 -> (currently unused)
   225  	//   PFD3 -> (currently unused)
   226  	Usb1PllConfig.Configure() // init USB1 PLL and PFDs
   227  	Usb2PllConfig.Configure() // init USB2 PLL
   228  
   229  	nxp.MuxIpPrePeriph.Mux(3)  // PRE_PERIPH select ARM_PLL
   230  	nxp.MuxIpPeriph.Mux(0)     // PERIPH select PRE_PERIPH
   231  	nxp.MuxIpPeriphClk2.Mux(1) // PERIPH_CLK2 select OSC
   232  	nxp.MuxIpPerclk.Mux(1)     // PERCLK select OSC
   233  
   234  	// set LVDS1 clock source
   235  	nxp.CCM_ANALOG.MISC1.Set((nxp.CCM_ANALOG.MISC1.Get() & ^uint32(nxp.CCM_ANALOG_MISC1_LVDS1_CLK_SEL_Msk)) |
   236  		((0 << nxp.CCM_ANALOG_MISC1_LVDS1_CLK_SEL_Pos) & nxp.CCM_ANALOG_MISC1_LVDS1_CLK_SEL_Msk))
   237  
   238  	// set CLOCK_OUT1 divider
   239  	nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO1_DIV_Msk)) |
   240  		((0 << nxp.CCM_CCOSR_CLKO1_DIV_Pos) & nxp.CCM_CCOSR_CLKO1_DIV_Msk))
   241  	// set CLOCK_OUT1 source
   242  	nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO1_SEL_Msk)) |
   243  		((1 << nxp.CCM_CCOSR_CLKO1_SEL_Pos) & nxp.CCM_CCOSR_CLKO1_SEL_Msk))
   244  	// set CLOCK_OUT2 divider
   245  	nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO2_DIV_Msk)) |
   246  		((0 << nxp.CCM_CCOSR_CLKO2_DIV_Pos) & nxp.CCM_CCOSR_CLKO2_DIV_Msk))
   247  	// set CLOCK_OUT2 source
   248  	nxp.CCM.CCOSR.Set((nxp.CCM.CCOSR.Get() & ^uint32(nxp.CCM_CCOSR_CLKO2_SEL_Msk)) |
   249  		((18 << nxp.CCM_CCOSR_CLKO2_SEL_Pos) & nxp.CCM_CCOSR_CLKO2_SEL_Msk))
   250  
   251  	nxp.CCM.CCOSR.ClearBits(nxp.CCM_CCOSR_CLK_OUT_SEL_Msk) // set CLK_OUT1 drives CLK_OUT
   252  	nxp.CCM.CCOSR.SetBits(nxp.CCM_CCOSR_CLKO1_EN_Msk)      // enable CLK_OUT1
   253  	nxp.CCM.CCOSR.SetBits(nxp.CCM_CCOSR_CLKO2_EN_Msk)      // enable CLK_OUT2
   254  
   255  	nxp.ClockIpIomuxcGpr.Enable(false) // disable IOMUXC_GPR
   256  	nxp.ClockIpIomuxc.Enable(false)    // disable IOMUXC
   257  	// set GPT1 High frequency reference clock source
   258  	nxp.IOMUXC_GPR.GPR5.ClearBits(nxp.IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT1_Msk)
   259  	// set GPT2 High frequency reference clock source
   260  	nxp.IOMUXC_GPR.GPR5.ClearBits(nxp.IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_Msk)
   261  
   262  	nxp.ClockIpGpio1.Enable(false) // disable GPIO
   263  	nxp.ClockIpGpio2.Enable(false) //
   264  	nxp.ClockIpGpio3.Enable(false) //
   265  	nxp.ClockIpGpio4.Enable(false) //
   266  }
   267  
   268  func enableTimerClocks() {
   269  	nxp.ClockIpGpt1.Enable(true)  // enable GPT/PIT
   270  	nxp.ClockIpGpt1S.Enable(true) //
   271  	nxp.ClockIpGpt2.Enable(true)  //
   272  	nxp.ClockIpGpt2S.Enable(true) //
   273  	nxp.ClockIpPit.Enable(true)   //
   274  }
   275  
   276  func enablePinClocks() {
   277  	nxp.ClockIpIomuxcGpr.Enable(true) // enable IOMUXC
   278  	nxp.ClockIpIomuxc.Enable(true)    //
   279  
   280  	nxp.ClockIpGpio1.Enable(true) // enable GPIO
   281  	nxp.ClockIpGpio2.Enable(true) //
   282  	nxp.ClockIpGpio3.Enable(true) //
   283  	nxp.ClockIpGpio4.Enable(true) //
   284  }
   285  
   286  func enablePeripheralClocks() {
   287  	nxp.ClockIpAdc1.Enable(true) // enable ADC
   288  	nxp.ClockIpAdc2.Enable(true) //
   289  
   290  	nxp.ClockIpXbar1.Enable(true) // enable XBAR
   291  	nxp.ClockIpXbar2.Enable(true) //
   292  	nxp.ClockIpXbar3.Enable(true) //
   293  
   294  	nxp.ClockIpUsdhc1.Enable(true) // enable USDHC
   295  	nxp.ClockIpUsdhc2.Enable(true) //
   296  
   297  	nxp.ClockIpSemc.Enable(true) // enable SEMC
   298  
   299  	nxp.ClockIpFlexSpi2.Enable(true) // enable FLEXSPI2
   300  
   301  	nxp.ClockIpLpspi1.Enable(true) // enable LPSPI
   302  	nxp.ClockIpLpspi2.Enable(true) //
   303  	nxp.ClockIpLpspi3.Enable(true) //
   304  	nxp.ClockIpLpspi4.Enable(true) //
   305  
   306  	nxp.ClockIpLpi2c1.Enable(true) // enable LPI2C
   307  	nxp.ClockIpLpi2c2.Enable(true) //
   308  	nxp.ClockIpLpi2c3.Enable(true) //
   309  	nxp.ClockIpLpi2c4.Enable(true) //
   310  
   311  	nxp.ClockIpCan1.Enable(true)  // enable CAN
   312  	nxp.ClockIpCan2.Enable(true)  //
   313  	nxp.ClockIpCan3.Enable(true)  //
   314  	nxp.ClockIpCan1S.Enable(true) //
   315  	nxp.ClockIpCan2S.Enable(true) //
   316  	nxp.ClockIpCan3S.Enable(true) //
   317  
   318  	nxp.ClockIpLpuart1.Enable(true) // enable UART
   319  	nxp.ClockIpLpuart2.Enable(true) //
   320  	nxp.ClockIpLpuart3.Enable(true) //
   321  	nxp.ClockIpLpuart4.Enable(true) //
   322  	nxp.ClockIpLpuart5.Enable(true) //
   323  	nxp.ClockIpLpuart6.Enable(true) //
   324  	nxp.ClockIpLpuart7.Enable(true) //
   325  	nxp.ClockIpLpuart8.Enable(true) //
   326  
   327  	nxp.ClockIpFlexio1.Enable(true) // enable FLEXIO
   328  	nxp.ClockIpFlexio2.Enable(true) //
   329  }