Merge pull request #1106 from martinling/pll-startup
Implement NXP's recommended setup sequence for the PLL and M4 clock
This commit is contained in:
@ -46,7 +46,6 @@
|
|||||||
|
|
||||||
#include "gpio_lpc.h"
|
#include "gpio_lpc.h"
|
||||||
|
|
||||||
#define WAIT_CPU_CLOCK_INIT_DELAY (10000)
|
|
||||||
/* GPIO Output PinMux */
|
/* GPIO Output PinMux */
|
||||||
static struct gpio_t gpio_led[] = {
|
static struct gpio_t gpio_led[] = {
|
||||||
GPIO(2, 1),
|
GPIO(2, 1),
|
||||||
@ -299,6 +298,19 @@ void delay(uint32_t duration)
|
|||||||
__asm__("nop");
|
__asm__("nop");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delay_us_at_mhz(uint32_t us, uint32_t mhz)
|
||||||
|
{
|
||||||
|
// The loop below takes 4 cycles per iteration.
|
||||||
|
uint32_t loop_iterations = (us * mhz) / 4;
|
||||||
|
asm volatile (
|
||||||
|
"start%=:\n"
|
||||||
|
" subs %[ITERATIONS], #1\n" // 1 cycle
|
||||||
|
" bpl start%=\n" // 3 cycles
|
||||||
|
:
|
||||||
|
: [ITERATIONS] "r" (loop_iterations)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* GCD algo from wikipedia */
|
/* GCD algo from wikipedia */
|
||||||
/* http://en.wikipedia.org/wiki/Greatest_common_divisor */
|
/* http://en.wikipedia.org/wiki/Greatest_common_divisor */
|
||||||
static uint32_t
|
static uint32_t
|
||||||
@ -485,54 +497,65 @@ This function shall be called after cpu_clock_init().
|
|||||||
*/
|
*/
|
||||||
static void cpu_clock_pll1_max_speed(void)
|
static void cpu_clock_pll1_max_speed(void)
|
||||||
{
|
{
|
||||||
uint32_t pll_reg;
|
uint32_t reg_val;
|
||||||
|
|
||||||
/* Configure PLL1 to Intermediate Clock (between 90 MHz and 110 MHz) */
|
/* This function implements the sequence recommended in:
|
||||||
/* Integer mode:
|
* UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */
|
||||||
FCLKOUT = M*(FCLKIN/N)
|
|
||||||
FCCO = 2*P*FCLKOUT = 2*P*M*(FCLKIN/N)
|
/* 1. Select the IRC as BASE_M4_CLK source. */
|
||||||
*/
|
reg_val = CGU_BASE_M4_CLK;
|
||||||
pll_reg = CGU_PLL1_CTRL;
|
reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK;
|
||||||
/* Clear PLL1 bits */
|
reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) |
|
||||||
pll_reg &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | CGU_PLL1_CTRL_PD_MASK | CGU_PLL1_CTRL_FBSEL_MASK | /* CLK SEL, PowerDown , FBSEL */
|
CGU_BASE_M4_CLK_AUTOBLOCK(1);
|
||||||
CGU_PLL1_CTRL_BYPASS_MASK | /* BYPASS */
|
CGU_BASE_M4_CLK = reg_val;
|
||||||
CGU_PLL1_CTRL_DIRECT_MASK | /* DIRECT */
|
|
||||||
CGU_PLL1_CTRL_PSEL_MASK | CGU_PLL1_CTRL_MSEL_MASK | CGU_PLL1_CTRL_NSEL_MASK ); /* PSEL, MSEL, NSEL- divider ratios */
|
/* 2. Enable the crystal oscillator. */
|
||||||
/* Set PLL1 up to 12MHz * 8 = 96MHz. */
|
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK;
|
||||||
pll_reg |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
|
|
||||||
| CGU_PLL1_CTRL_PSEL(0)
|
/* 3. Wait 250us. */
|
||||||
| CGU_PLL1_CTRL_NSEL(0)
|
delay_us_at_mhz(250, 12);
|
||||||
| CGU_PLL1_CTRL_MSEL(7)
|
|
||||||
| CGU_PLL1_CTRL_FBSEL(1);
|
/* 4. Set the AUTOBLOCK bit. */
|
||||||
CGU_PLL1_CTRL = pll_reg;
|
CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1);
|
||||||
/* wait until stable */
|
|
||||||
|
/* 5. Reconfigure PLL1 to produce the final output frequency, with the
|
||||||
|
* crystal oscillator as clock source. */
|
||||||
|
reg_val = CGU_PLL1_CTRL;
|
||||||
|
reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK |
|
||||||
|
CGU_PLL1_CTRL_PD_MASK |
|
||||||
|
CGU_PLL1_CTRL_FBSEL_MASK |
|
||||||
|
CGU_PLL1_CTRL_BYPASS_MASK |
|
||||||
|
CGU_PLL1_CTRL_DIRECT_MASK |
|
||||||
|
CGU_PLL1_CTRL_PSEL_MASK |
|
||||||
|
CGU_PLL1_CTRL_MSEL_MASK |
|
||||||
|
CGU_PLL1_CTRL_NSEL_MASK );
|
||||||
|
/* Set PLL1 up to 12MHz * 17 = 204MHz.
|
||||||
|
* Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */
|
||||||
|
reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) |
|
||||||
|
CGU_PLL1_CTRL_PSEL(0) |
|
||||||
|
CGU_PLL1_CTRL_NSEL(0) |
|
||||||
|
CGU_PLL1_CTRL_MSEL(16) |
|
||||||
|
CGU_PLL1_CTRL_FBSEL(0) |
|
||||||
|
CGU_PLL1_CTRL_DIRECT(1);
|
||||||
|
CGU_PLL1_CTRL = reg_val;
|
||||||
|
|
||||||
|
/* 6. Wait for PLL1 to lock. */
|
||||||
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK));
|
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK));
|
||||||
|
|
||||||
/* use PLL1 as clock source for BASE_M4_CLK (CPU) */
|
/* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */
|
||||||
CGU_BASE_M4_CLK = (CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1) | CGU_BASE_M4_CLK_AUTOBLOCK(1));
|
CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK;
|
||||||
|
|
||||||
/* Wait before to switch to max speed */
|
/* 8. Select PLL1 as BASE_M4_CLK source. */
|
||||||
delay(WAIT_CPU_CLOCK_INIT_DELAY);
|
reg_val = CGU_BASE_M4_CLK;
|
||||||
|
reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK;
|
||||||
|
reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
CGU_BASE_M4_CLK = reg_val;
|
||||||
|
|
||||||
/* Configure PLL1 Max Speed */
|
/* 9. Wait 50us. */
|
||||||
/* Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */
|
delay_us_at_mhz(50, 104);
|
||||||
pll_reg = CGU_PLL1_CTRL;
|
|
||||||
/* Clear PLL1 bits */
|
|
||||||
pll_reg &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | CGU_PLL1_CTRL_PD_MASK | CGU_PLL1_CTRL_FBSEL_MASK | /* CLK SEL, PowerDown , FBSEL */
|
|
||||||
CGU_PLL1_CTRL_BYPASS_MASK | /* BYPASS */
|
|
||||||
CGU_PLL1_CTRL_DIRECT_MASK | /* DIRECT */
|
|
||||||
CGU_PLL1_CTRL_PSEL_MASK | CGU_PLL1_CTRL_MSEL_MASK | CGU_PLL1_CTRL_NSEL_MASK ); /* PSEL, MSEL, NSEL- divider ratios */
|
|
||||||
/* Set PLL1 up to 12MHz * 17 = 204MHz. */
|
|
||||||
pll_reg |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
|
|
||||||
| CGU_PLL1_CTRL_PSEL(0)
|
|
||||||
| CGU_PLL1_CTRL_NSEL(0)
|
|
||||||
| CGU_PLL1_CTRL_MSEL(16)
|
|
||||||
| CGU_PLL1_CTRL_FBSEL(1)
|
|
||||||
| CGU_PLL1_CTRL_DIRECT(1);
|
|
||||||
CGU_PLL1_CTRL = pll_reg;
|
|
||||||
/* wait until stable */
|
|
||||||
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK));
|
|
||||||
|
|
||||||
|
/* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */
|
||||||
|
CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clock startup for LPC4320 configure PLL1 to max speed (204MHz).
|
/* clock startup for LPC4320 configure PLL1 to max speed (204MHz).
|
||||||
@ -598,14 +621,7 @@ void cpu_clock_init(void)
|
|||||||
/* set xtal oscillator to low frequency mode */
|
/* set xtal oscillator to low frequency mode */
|
||||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK;
|
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK;
|
||||||
|
|
||||||
/* power on the oscillator and wait until stable */
|
cpu_clock_pll1_max_speed();
|
||||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK;
|
|
||||||
|
|
||||||
/* Wait about 100us after Crystal Power ON */
|
|
||||||
delay(WAIT_CPU_CLOCK_INIT_DELAY);
|
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for BASE_M4_CLK (CPU) */
|
|
||||||
CGU_BASE_M4_CLK = (CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_XTAL) | CGU_BASE_M4_CLK_AUTOBLOCK(1));
|
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for APB1 */
|
/* use XTAL_OSC as clock source for APB1 */
|
||||||
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK(1)
|
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK(1)
|
||||||
@ -615,8 +631,6 @@ void cpu_clock_init(void)
|
|||||||
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1)
|
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1)
|
||||||
| CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL);
|
| CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||||
|
|
||||||
cpu_clock_pll1_max_speed();
|
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for PLL0USB */
|
/* use XTAL_OSC as clock source for PLL0USB */
|
||||||
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1)
|
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1)
|
||||||
| CGU_PLL0USB_CTRL_AUTOBLOCK(1)
|
| CGU_PLL0USB_CTRL_AUTOBLOCK(1)
|
||||||
|
Reference in New Issue
Block a user