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.
This commit is contained in:
Ville Juven 2024-04-24 14:42:53 +03:00 committed by Alan Carvalho de Assis
parent e3f4749a3c
commit 0d9a3d94eb
7 changed files with 178 additions and 79 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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_*/

View File

@ -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"

View File

@ -30,6 +30,8 @@
#include <sys/param.h>
#include <sys/types.h>
#include <arch/board/board.h>
#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
}
/****************************************************************************

View File

@ -29,6 +29,85 @@
#include <stdint.h>
/****************************************************************************
* 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
****************************************************************************/

View File

@ -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
****************************************************************************/