From 0d9a3d94eb15f36e61dfc4373a20eb7dfdc110ed Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 24 Apr 2024 14:42:53 +0300 Subject: [PATCH] imx9_clockconfig: Add way to set PLL frequencies This patch adds a way to configure PLL frequencies. The configuration is given by board logic. These values should only be modified by the bootloader, but we don't have that yet so the flag is never activated. --- arch/arm64/src/imx9/Kconfig | 4 - .../arm64/src/imx9/hardware/imx93/imx93_ccm.h | 10 ++ .../arm64/src/imx9/hardware/imx93/imx93_pll.h | 33 +------ arch/arm64/src/imx9/imx9_boot.c | 1 + arch/arm64/src/imx9/imx9_clockconfig.c | 97 +++++++++++-------- arch/arm64/src/imx9/imx9_clockconfig.h | 79 +++++++++++++++ boards/arm64/imx9/imx93-evk/include/board.h | 33 +++++++ 7 files changed, 178 insertions(+), 79 deletions(-) diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index f7809bc8be..ba72f37268 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -310,10 +310,6 @@ config IMX9_LPSPI bool "LPSPI support" default n -config IMX9_PLL - bool "PLL setup support" - default n - menu "LPI2C Peripherals" menuconfig IMX9_LPI2C1 diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h index 6b43fb7edc..a86f4e72f2 100644 --- a/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h @@ -168,6 +168,10 @@ #define CCM_GPR_SH_GPR_SHIFT (0) /* Bits 0-31: General purpose register, shared for all CPU domains (GPR) */ #define CCM_GPR_SH_GPR_MASK (0xffffffff << CCM_GPR_SH_GPR_SHIFT) +#define CCM_GPR_A55_CLK_SEL_SHIFT (0) +#define CCM_GPR_A55_CLK_SEL_MASK (0x01 << CCM_GPR_A55_CLK_SEL_SHIFT) +#define CCM_GPR_A55_CLK_SEL_CCM (0 << 0) +#define CCM_GPR_A55_CLK_SEL_PLL (1 << 0) /* General Purpose Register (GPR_SHAREDn_AUTHEN, n=0..7) */ @@ -561,6 +565,12 @@ #define CCM_LPCG_TMC 125 #define CCM_LPCG_PMRO 126 +/* Shared register indices */ + +#define CCM_SHARED_EXT_CLK 0 +#define CCM_SHARED_A55_CLK 1 +#define CCM_SHARED_DRAM_CLK 2 + /* Other parameters */ #define ROOT_MUX_MAX 4 /* Count of root clock MUX options */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h b/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h index 31dbb7c0d3..fb0a5af737 100644 --- a/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h @@ -175,7 +175,7 @@ #define PLL_DFS_MFN_MASK (0x7 << PLL_DFS_MFN_SHIFT) #define PLL_DFS_MFN(n) (((n) << PLL_DFS_MFN_SHIFT) & PLL_DFS_MFN_MASK) #define PLL_DFS_MFI_SHIFT (8) /* Bits 8-15: MFI */ -#define PLL_DFS_MFI_MASK (0xFF << PLL_DFS_MFI_SHIFT) +#define PLL_DFS_MFI_MASK (0xff << PLL_DFS_MFI_SHIFT) #define PLL_DFS_MFI(n) (((n) << PLL_DFS_MFI_SHIFT) & PLL_DFS_MFI_MASK) /* PLL Dividers (DIV) */ @@ -192,35 +192,4 @@ #define PLL_DFS_STATUS_DFS_OK_MASK (0x7 << PLL_DFS_STATUS_DFS_OK_SHIFT) #define PLL_DFS_STATUS_DFS_OK(n) (((n) << PLL_DFS_STATUS_DFS_OK_SHIFT) & PLL_DFS_STATUS_DFS_OK_MASK) -/**************************************************************************** - * Public Types - ****************************************************************************/ - -struct pll_parms -{ - /* Integer part (DIV) */ - - struct - { - uint32_t rdiv; /* Input clock divider */ - uint32_t odiv; /* PLL output divider */ - uint32_t mfi; /* PLL integer divider */ - }; - - /* Fractional part (NUMERATOR / DENOMINATOR) */ - - struct - { - uint32_t mfn; /* PLL fractional divider numerator */ - uint32_t mfd; /* PLL fractional divider denominator */ - }; -}; - -struct pfd_parms -{ - uint32_t mfi; /* PLL integer divider */ - uint32_t mfn; /* PLL fractional divider numerator */ - bool divby2_en; /* Enable the divide-by-2 output */ -}; - #endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PLL_H_*/ diff --git a/arch/arm64/src/imx9/imx9_boot.c b/arch/arm64/src/imx9/imx9_boot.c index 121c228197..eb4e7e69d2 100644 --- a/arch/arm64/src/imx9/imx9_boot.c +++ b/arch/arm64/src/imx9/imx9_boot.c @@ -39,6 +39,7 @@ #include "arm64_mmu.h" #include "imx9_boot.h" +#include "imx9_clockconfig.h" #include "imx9_serial.h" #include "imx9_gpio.h" #include "imx9_lowputc.h" diff --git a/arch/arm64/src/imx9/imx9_clockconfig.c b/arch/arm64/src/imx9/imx9_clockconfig.c index a5a5238afb..ac3f976801 100644 --- a/arch/arm64/src/imx9/imx9_clockconfig.c +++ b/arch/arm64/src/imx9/imx9_clockconfig.c @@ -30,6 +30,8 @@ #include #include +#include + #include "barriers.h" #include "arm64_internal.h" @@ -42,6 +44,12 @@ * Pre-processor Definitions ****************************************************************************/ +/* The base oscillator frequency is 24MHz */ + +#define XTAL_FREQ 24000000u + +/* Common barrier */ + #define mb() \ do \ { \ @@ -50,16 +58,12 @@ } \ while (0) -/* The base oscillator frequency is 24MHz */ - -#define XTAL_FREQ 24000000u - /**************************************************************************** * Private Functions ****************************************************************************/ -#ifdef CONFIG_IMX9_PLL -static int pll_init(uintptr_t reg, bool frac, struct pll_parms *parm) +#ifdef CONFIG_IMX9_BOOTLOADER +static int pll_init(uintptr_t reg, bool frac, struct pll_parms_s *parm) { uint32_t val; @@ -104,7 +108,7 @@ static int pll_init(uintptr_t reg, bool frac, struct pll_parms *parm) return OK; } -static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms *pfdparm) +static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms_s *pfdparm) { uint32_t ctrl; uint32_t div; @@ -136,12 +140,13 @@ static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms *pfdparm) /* Bypass and disable DFS */ putreg32(PLL_DFS_BYPASS_EN, PLL_SET(ctrl)); - putreg32(PLL_DFS_CLKOUT_EN | PLL_DFS_ENABLE, PLL_CLR(ctrl)); + putreg32(PLL_DFS_CLKOUT_EN | PLL_DFS_CLKOUT_DIVBY2_EN | PLL_DFS_ENABLE, + PLL_CLR(ctrl)); /* Set the divider */ val = PLL_DFS_MFI(pfdparm->mfi) | PLL_DFS_MFN(pfdparm->mfn); - putreg32(val, PLL_SET(div)); + putreg32(val, PLL_VAL(div)); /* Enable (or disable) the divby2 output */ @@ -163,10 +168,16 @@ static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms *pfdparm) while (!(getreg32(PLL_DFS_STATUS(reg)) & (1 << pfd))); + /* Then disable bypass */ + + putreg32(PLL_DFS_BYPASS_EN, PLL_CLR(ctrl)); + mb(); + return OK; } +#endif -static uint32_t calculate_vco_freq(const struct pll_parms *parm, bool frac) +static uint32_t calculate_vco_freq(const struct pll_parms_s *parm, bool frac) { /* Base clock is common for all VCO:s */ @@ -183,7 +194,7 @@ static uint32_t calculate_vco_freq(const struct pll_parms *parm, bool frac) static uint32_t vco_freq_out(uintptr_t reg, bool frac) { - struct pll_parms parm; + struct pll_parms_s parm; uint32_t ctrl; uint32_t status; uint32_t div; @@ -193,7 +204,6 @@ static uint32_t vco_freq_out(uintptr_t reg, bool frac) ctrl = getreg32(PLL_CTRL(reg)); if ((ctrl & PLL_CTRL_POWERUP) == 0) { - return 0; } @@ -202,7 +212,6 @@ static uint32_t vco_freq_out(uintptr_t reg, bool frac) status = getreg32(PLL_PLL_STATUS(reg)); if ((status & PLL_PLL_STATUS_PLL_LOCK) == 0) { - return 0; } @@ -250,7 +259,6 @@ static uint32_t pll_freq_out(uintptr_t reg, bool frac) if ((ctrl & PLL_CTRL_CLKMUX_EN) == 0) { - return 0; } @@ -284,7 +292,7 @@ static uint32_t pll_freq_out(uintptr_t reg, bool frac) static uint32_t pll_pfd_freq_out(uintptr_t reg, int pfd, int div2) { - struct pfd_parms parm; + struct pfd_parms_s parm; uint32_t ctrl; uint32_t div; uint32_t vco; @@ -338,14 +346,12 @@ static uint32_t pll_pfd_freq_out(uintptr_t reg, int pfd, int div2) /* Populate the DFS parameters */ - parm.mfi = (div & PLL_DFS_MFI_MASK) >> PLL_DFS_MFI_SHIFT; - parm.mfn = (div & PLL_DFS_MFN_MASK) >> PLL_DFS_MFN_SHIFT; + parm.mfi = (div & PLL_DFS_MFI_MASK) >> PLL_DFS_MFI_SHIFT; + parm.mfn = (div & PLL_DFS_MFN_MASK) >> PLL_DFS_MFN_SHIFT; - return ((uint64_t)vco * 5) / (parm.mfi * 5 + parm.mfn) / div2; + return ((uint64_t)vco * 5) / (parm.mfi * 5 + parm.mfn) / div2; } -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -362,29 +368,34 @@ static uint32_t pll_pfd_freq_out(uintptr_t reg, int pfd, int div2) void imx9_clockconfig(void) { - /* REVISIT: Define a clock config and run it. For now we rely on the fact - * that the boot code + bootloader will have set us up. - * - * During boot the ROM code initializes the PLL clocks as follows: - * - * - OSC24M : 24 MHz - * - ARMPLL : 2000 MHz - * - ARMPLL_OUT : 2000 MHz - * - DRAMPLL : 1000 MHz - * - SYSPLL1 : 4000 MHz - * - SYSPLL_PFD0 : 1000 MHz - * - SYSPLL_PFD1 : 800 MHz - * - SYSPLL_PFD2 : 625 MHz - * - AUDIOPLL : OFF - * - AUDIOPLL_OUT : OFF - * - VIDEOPLL : OFF - * - VIDEOPLL_OUT : OFF - * - * After reset all clock sources (OSCPLL) and root clocks (CLOCK_ROOT) are - * running, but gated (LPCG). - * - * By default, all peripheral root clocks are set to the 24 MHz oscillator. - */ +#ifdef CONFIG_IMX9_BOOTLOADER + struct imx9_pll_cfg_s pll_cfgs[] = PLL_CFGS; + struct imx9_pfd_cfg_s pfd_cfgs[] = PFD_CFGS; + struct imx9_pll_cfg_s pll_arm = ARMPLL_CFG; + int i; + + /* Set the CPU clock */ + + putreg32(IMX9_CCM_GPR_SH_CLR(CCM_SHARED_A55_CLK), CCM_GPR_A55_CLK_SEL_PLL); + pll_init(pll_arm.reg, pll_arm.frac, &pll_arm.parms); + putreg32(IMX9_CCM_GPR_SH_SET(CCM_SHARED_A55_CLK), CCM_GPR_A55_CLK_SEL_PLL); + + /* Run the PLL configuration */ + + for (i = 0; i < nitems(pll_cfgs); i++) + { + struct imx9_pll_cfg_s *cfg = &pll_cfgs[i]; + pll_init(cfg->reg, cfg->frac, &cfg->parms); + } + + /* Run the PFD configuration */ + + for (i = 0; i < nitems(pfd_cfgs); i++) + { + struct imx9_pfd_cfg_s *cfg = &pfd_cfgs[i]; + pll_pfd_init(cfg->reg, cfg->pfd, &cfg->parms); + } +#endif } /**************************************************************************** diff --git a/arch/arm64/src/imx9/imx9_clockconfig.h b/arch/arm64/src/imx9/imx9_clockconfig.h index 90301989a9..cf8ffc1f45 100644 --- a/arch/arm64/src/imx9/imx9_clockconfig.h +++ b/arch/arm64/src/imx9/imx9_clockconfig.h @@ -29,6 +29,85 @@ #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PLL_PARMS(_rdiv, _odiv, _mfi, _mfn, _mfd) \ + { \ + .rdiv = (_rdiv), \ + .odiv = (_odiv), \ + .mfi = (_mfi), \ + .mfn = (_mfn), \ + .mfd = (_mfd), \ + } + +#define PLL_CFG(_reg, _frac, _parms) \ + { \ + .reg = (_reg), \ + .frac = (_frac), \ + .parms = _parms, \ + } + +#define PFD_PARMS(_mfi, _mfn, _div2) \ + { \ + .mfi = (_mfi), \ + .mfn = (_mfn), \ + .divby2_en = (_div2) \ + } + +#define PFD_CFG(_reg, _pfd, _parms) \ + { \ + .reg = (_reg), \ + .pfd = (_pfd), \ + .parms = _parms, \ + } + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct pll_parms_s +{ + /* Integer part (DIV) */ + + struct + { + uint32_t rdiv; /* Input clock divider */ + uint32_t odiv; /* PLL output divider */ + uint32_t mfi; /* PLL integer divider */ + }; + + /* Fractional part (NUMERATOR / DENOMINATOR) */ + + struct + { + uint32_t mfn; /* PLL fractional divider numerator */ + uint32_t mfd; /* PLL fractional divider denominator */ + }; +}; + +struct pfd_parms_s +{ + uint32_t mfi; /* PLL integer divider */ + uint32_t mfn; /* PLL fractional divider numerator */ + bool divby2_en; /* Enable the divide-by-2 output */ +}; + +struct imx9_pll_cfg_s +{ + uintptr_t reg; /* The PLL register base */ + bool frac; /* Fractional PLL ? */ + struct pll_parms_s parms; /* The PLL parameters */ +}; + +struct imx9_pfd_cfg_s +{ + uintptr_t reg; /* The PLL register base */ + int pfd; /* The PFD number */ + struct pfd_parms_s parms; /* The PFD parameters */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h index d1a74a7e5a..4632d5443e 100644 --- a/boards/arm64/imx9/imx93-evk/include/board.h +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -88,6 +88,39 @@ #define MUX_LPSPI6_CS IOMUX_CFG(IOMUXC_PAD_GPIO_IO00_GPIO2_IO00, IOMUX_GPIO_DEFAULT, IOMUXC_MUX_SION_ON) #define GPIO_LPSPI6_CS (GPIO_PORT2 | GPIO_PIN0 | GPIO_OUTPUT | GPIO_OUTPUT_ONE) +/* Set the PLL clocks as follows: + * + * - OSC24M : 24 MHz + * - ARMPLL_OUT : 1692 MHz + * - DRAMPLL : 933 MHz + * - SYSPLL1 : 4000 MHz + * - SYSPLL_PFD0 : 1000 MHz + * - SYSPLL_PFD1 : 800 MHz + * - SYSPLL_PFD2 : 625 MHz + * - AUDIOPLL_OUT : OFF + * - VIDEOPLL_OUT : OFF + * + * After reset all clock sources (OSCPLL) and root clocks (CLOCK_ROOT) are + * running, but gated (LPCG). + * + * By default, all peripheral root clocks are set to the 24 MHz oscillator. + */ + +#define ARMPLL_CFG PLL_CFG(IMX9_ARMPLL_BASE, false, PLL_PARMS(1, 2, 141, 0, 0)) +#define DRAMPLL_CFG PLL_CFG(IMX9_DRAMPLL_BASE, true, PLL_PARMS(1, 2, 155, 1, 2)) + +#define PLL_CFGS \ + { \ + PLL_CFG(IMX9_SYSPLL_BASE, true, PLL_PARMS(1, 4, 166, 2, 3)), \ + } + +#define PFD_CFGS \ + { \ + PFD_CFG(IMX9_SYSPLL_BASE, 0, PFD_PARMS(4, 0, true)), \ + PFD_CFG(IMX9_SYSPLL_BASE, 1, PFD_PARMS(5, 0, true)), \ + PFD_CFG(IMX9_SYSPLL_BASE, 2, PFD_PARMS(6, 2, true)), \ + } + /**************************************************************************** * Public Data ****************************************************************************/