arm64/imx9: ccm: add default clk init

This adds enablers for setting various clocks to some default
values. Also, this provides helpers to grant nonsecure access
to a number of clocks. Bootloader may utilize these to make
the system boot in a deterministic manner.

Signed-off-by: Eero Nurkkala <eero.nurkkala@offcode.fi>
This commit is contained in:
Eero Nurkkala 2024-07-09 11:00:06 +03:00 committed by Alan Carvalho de Assis
parent db24702fc5
commit 48cf91a7be
5 changed files with 486 additions and 8 deletions

View File

@ -158,7 +158,7 @@
#define CCM_CR_AUTH_TZ_USER (1 << 8) /* Bit 8: Clock root can be changed in user mode (TZ_USER) */
#define CCM_CR_AUTH_TZ_NS (1 << 9) /* Bit 9: Clock root can be changed in non-secure mode (TZ_NS) */
/* Bit 10: Reserved */
#define CCM_CR_AUTH_LOCK_TZ (1 << 11) /* Bit 1: Lock TrustZone settings (LOCK_TZ) */
#define CCM_CR_AUTH_LOCK_TZ (1 << 11) /* Bit 11: Lock TrustZone settings (LOCK_TZ) */
/* Bits 12-14: Reserved */
#define CCM_CR_AUTH_LOCK_LIST (1 << 12) /* Bit 15: Lock whitelist settings (LOCK_LIST) */
#define CCM_CR_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */
@ -337,6 +337,12 @@
#define CCM_LPCG_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */
#define CCM_LPCG_AUTH_WHITE_LIST_MASK (0xffff << CCM_LPCG_AUTH_WHITE_LIST_SHIFT)
/* Auth access bits */
#define CCM_AUTH_TZ_USER(n) ((n) << 8)
#define CCM_AUTH_TZ_NS(n) ((n) << 9)
#define CCM_AUTH_LOCK_TZ(n) ((n) << 11)
/* Clock roots */
#define CCM_CR_A55PERIPH 0 /* CLOCK Root Arm A55 Periph. */
@ -570,12 +576,14 @@
#define CCM_SHARED_EXT_CLK 0
#define CCM_SHARED_A55_CLK 1
#define CCM_SHARED_DRAM_CLK 2
#define CCM_SHARED_GPR_COUNT 7
/* Other parameters */
#define ROOT_MUX_MAX 4 /* Count of root clock MUX options */
#define CCM_CR_COUNT 94 /* Count of clock roots */
#define CCM_LPCG_COUNT 126 /* Counte of clock gates */
#define CCM_LPCG_COUNT 126 /* Count of clock gates */
#define CCM_OSCPLL_COUNT 18 /* Count of osc plls */
/****************************************************************************
* Public Types
@ -708,4 +716,30 @@ static const int g_ccm_root_mux[][ROOT_MUX_MAX] =
{OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD2}, /* Pal Came Scan */
};
#define CCM_ARM_A55_PERIPH_CLK_ROOT 0
#define CCM_ARM_A55_MTR_BUS_CLK_ROOT 1
#define CCM_ARM_A55_CLK_ROOT 2
#define CCM_M33_CLK_ROOT 3
#define CCM_ELE_CLK_ROOT 4
#define CCM_BUS_WAKEUP_CLK_ROOT 5
#define CCM_BUS_AON_CLK_ROOT 6
#define CCM_WAKEUP_AXI_CLK_ROOT 7
#define CCM_SWO_TRACE_CLK_ROOT 8
#define CCM_M33_SYSTICK_CLK_ROOT 9
#define CCM_NIC_CLK_ROOT 65
#define CCM_NIC_APB_CLK_ROOT 66
#define CCM_DRAM_ALT_CLK_ROOT 76
#define CCM_DRAM_APB_CLK_ROOT 77
#define CCM_CLK_ROOT_NUM 95
#define CCM_OSCPLL_END 19
#define CCM_CCGR_NUM 127
#define CCM_SHARED_GPR_DRAM_CLK 2
#define CCM_SHARED_GPR_DRAM_CLK_SEL_PLL 0
#define CCM_SHARED_GPR_DRAM_CLK_SEL_CCM BIT(0)
#define CCM_SHARED_GPR_NUM 8
#define MHZ(x) ((x) * 1000000UL)
#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_CCM_H */

View File

@ -49,6 +49,206 @@
} \
while (0)
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ccm_clk_src_tz_access
*
* Description:
* Clock source access contol enable.
*
* Input Parameters:
* pscll - Clock source
* non_secure - Grant non-secure access
* user_mode - Grant user mode access
* lock_tz - Lock settings
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned on
* failure.
*
****************************************************************************/
static int imx9_ccm_clk_src_tz_access(uint32_t oscpll, bool non_secure,
bool user_mode, bool lock_tz)
{
if (oscpll > CCM_OSCPLL_COUNT)
{
return -EINVAL;
}
modifyreg32(IMX9_CCM_OSCPLL_AUTH(oscpll), 0,
CCM_AUTH_TZ_USER(user_mode) |
CCM_AUTH_TZ_NS(non_secure) |
CCM_AUTH_LOCK_TZ(lock_tz));
return 0;
}
/****************************************************************************
* Name: ccm_clk_root_tz_access
*
* Description:
* Root clock access control enable.
*
* Input Parameters:
* clk_root_id - Root clock id
* non_secure - Grant non-secure access
* user_mode - Grant user mode access
* lock_tz - Lock settings
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned on
* failure.
*
****************************************************************************/
static int imx9_ccm_clk_root_tz_access(uint32_t clk_root_id, bool non_secure,
bool user_mode, bool lock_tz)
{
if (clk_root_id > CCM_CR_COUNT)
{
return -EINVAL;
}
modifyreg32(IMX9_CCM_CR_AUTH(clk_root_id), 0,
CCM_AUTH_TZ_USER(user_mode) |
CCM_AUTH_TZ_NS(non_secure) |
CCM_AUTH_LOCK_TZ(lock_tz));
return 0;
}
/****************************************************************************
* Name: imx9_ccm_lpcg_tz_access
*
* Description:
* Low power clock gatig unit access enable.
*
* Input Parameters:
* lpcg - Clock id
* non_secure - Grant non-secure access
* user_mode - Grant user mode access
* lock_tz - Lock settings
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned on
* failure.
*
****************************************************************************/
static int imx9_ccm_lpcg_tz_access(uint32_t lpcg, bool non_secure,
bool user_mode, bool lock_tz)
{
if (lpcg > CCM_LPCG_COUNT)
{
return -EINVAL;
}
modifyreg32(IMX9_CCM_LPCG_AUTH(lpcg), 0,
CCM_AUTH_TZ_USER(user_mode) |
CCM_AUTH_TZ_NS(non_secure) |
CCM_AUTH_LOCK_TZ(lock_tz));
return 0;
}
/****************************************************************************
* Name: imx9_ccm_shared_gpr_tz_access
*
* Description:
* General purpose access enable.
*
* Input Parameters:
* grp - Gpr id
* non_secure - Grant non-secure access
* user_mode - Grant user mode access
* lock_tz - Lock settings
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned on
* failure.
*
****************************************************************************/
static int imx9_ccm_shared_gpr_tz_access(uint32_t gpr, bool non_secure,
bool user_mode, bool lock_tz)
{
if (gpr > CCM_SHARED_GPR_COUNT)
{
return -EINVAL;
}
modifyreg32(IMX9_CCM_GPR_SH_AUTH(gpr), 0,
CCM_AUTH_TZ_USER(user_mode) |
CCM_AUTH_TZ_NS(non_secure) |
CCM_AUTH_LOCK_TZ(lock_tz));
return 0;
}
/****************************************************************************
* Name: imx9_ccm_clock_prepare
*
* Description:
* Prepares the clocks, grants non-secure access for clocks.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero on success, a negated error code otherwise
*
****************************************************************************/
static int imx9_ccm_clock_prepare(void)
{
int ret;
int i;
/* allow for non-secure access */
for (i = 0; i < CCM_OSCPLL_END; i++)
{
ret = imx9_ccm_clk_src_tz_access(i, true, false, false);
if (ret != 0)
{
return ret;
}
}
for (i = 0; i < CCM_CLK_ROOT_NUM; i++)
{
ret = imx9_ccm_clk_root_tz_access(i, true, false, false);
if (ret != 0)
{
return ret;
}
}
for (i = 0; i < CCM_CCGR_NUM; i++)
{
ret = imx9_ccm_lpcg_tz_access(i, true, false, false);
if (ret != 0)
{
return ret;
}
}
for (i = 0; i < CCM_SHARED_GPR_NUM; i++)
{
ret = imx9_ccm_shared_gpr_tz_access(i, true, false, false);
if (ret != 0)
{
return ret;
}
}
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -195,3 +395,166 @@ int imx9_ccm_gate_on(int gate, bool enabled)
return OK;
}
/****************************************************************************
* Name: imx9_ccm_shared_gpr_set
*
* Description:
* Set shared gpr clock register value
*
* Input Parameters:
* gpr - General purpose clock index
* val - Value
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned on
* failure.
*
****************************************************************************/
int imx9_ccm_shared_gpr_set(uint32_t gpr, uint32_t val)
{
if (gpr > CCM_SHARED_GPR_COUNT)
{
return -EINVAL;
}
putreg32(val, IMX9_CCM_GPR_SH(gpr));
return 0;
}
/****************************************************************************
* Name: imx9_ccm_clock_init
*
* Description:
* Initializes bus clocks for a known default state.
*
* Input Parameters:
* None
*
* Returned Value:
* OK on success, a negated error value otherwise
*
****************************************************************************/
int imx9_ccm_clock_init(void)
{
int ret;
ret = imx9_ccm_clock_prepare();
if (ret != 0)
{
return ret;
}
/* Set A55 clk to 500M. This clock root is normally used as intermediate
* clock source for A55 core / DSU when doing ARM PLL reconfig. Set it to
* 500 MHz.
*/
ret = imx9_ccm_configure_root_clock(CCM_ARM_A55_CLK_ROOT, SYS_PLL1PFD0, 2);
if (ret != 0)
{
return ret;
}
/* Set A55 periphal to 333 MHz */
ret = imx9_ccm_configure_root_clock(CCM_ARM_A55_PERIPH_CLK_ROOT,
SYS_PLL1PFD0, 3);
if (ret != 0)
{
return ret;
}
/* Set A55 mtr bus to 133 MHz */
ret = imx9_ccm_configure_root_clock(CCM_ARM_A55_MTR_BUS_CLK_ROOT,
SYS_PLL1PFD1DIV2, 3);
if (ret != 0)
{
return ret;
}
/* ELE to 200 MHz */
ret = imx9_ccm_configure_root_clock(CCM_ELE_CLK_ROOT, SYS_PLL1PFD1DIV2, 2);
if (ret != 0)
{
return ret;
}
/* Bus_wakeup to 133 MHz */
ret = imx9_ccm_configure_root_clock(CCM_BUS_WAKEUP_CLK_ROOT,
SYS_PLL1PFD1DIV2, 3);
if (ret != 0)
{
return ret;
}
/* Bus_AON to 133 MHz */
ret = imx9_ccm_configure_root_clock(CCM_BUS_AON_CLK_ROOT, SYS_PLL1PFD1DIV2,
3);
if (ret != 0)
{
return ret;
}
/* M33 to 200 MHz */
ret = imx9_ccm_configure_root_clock(CCM_M33_CLK_ROOT, SYS_PLL1PFD1DIV2, 2);
if (ret != 0)
{
return ret;
}
/* WAKEUP_AXI to 312.5 MHz, because of FEC only can support to 320M for
* generating MII clock at 2.5 MHz
*/
ret = imx9_ccm_configure_root_clock(CCM_WAKEUP_AXI_CLK_ROOT, SYS_PLL1PFD2,
2);
if (ret != 0)
{
return ret;
}
/* SWO TRACE to 133 MHz */
ret = imx9_ccm_configure_root_clock(CCM_SWO_TRACE_CLK_ROOT,
SYS_PLL1PFD1DIV2, 3);
if (ret != 0)
{
return ret;
}
/* M33 systetick to 24 MHz */
ret = imx9_ccm_configure_root_clock(CCM_M33_SYSTICK_CLK_ROOT, OSC_24M, 1);
if (ret != 0)
{
return ret;
}
/* NIC to 400 MHz */
ret = imx9_ccm_configure_root_clock(CCM_NIC_CLK_ROOT, SYS_PLL1PFD1, 2);
if (ret != 0)
{
return ret;
}
/* NIC_APB to 133 MHz */
ret = imx9_ccm_configure_root_clock(CCM_NIC_APB_CLK_ROOT, SYS_PLL1PFD1DIV2,
3);
if (ret != 0)
{
return ret;
}
return OK;
}

View File

@ -85,4 +85,38 @@ int imx9_ccm_root_clock_on(int root, bool enabled);
int imx9_ccm_gate_on(int gate, bool enabled);
/****************************************************************************
* Name: imx9_ccm_shared_gpr_set
*
* Description:
* Set shared gpr clock register value
*
* Input Parameters:
* gpr - General purpose clock index
* val - Value
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned on
* failure.
*
****************************************************************************/
int imx9_ccm_shared_gpr_set(uint32_t gpr, uint32_t val);
/****************************************************************************
* Name: imx9_ccm_clock_init
*
* Description:
* Initializes bus clocks for a known default state.
*
* Input Parameters:
* None
*
* Returned Value:
* OK on success, a negated error value otherwise
*
****************************************************************************/
int imx9_ccm_clock_init(void);
#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_CCM_H */

View File

@ -67,6 +67,11 @@ static int pll_init(uintptr_t reg, bool frac, struct pll_parms_s *parm)
{
uint32_t val;
if (!frac)
{
modifyreg32(PLL_CLR(PLL_CTRL(reg)), 0, PLL_CTRL_HW_CTRL_SEL);
}
/* Bypass and disable PLL */
putreg32(PLL_CTRL_CLKMUX_BYPASS, PLL_SET(PLL_CTRL(reg)));
@ -80,14 +85,15 @@ static int pll_init(uintptr_t reg, bool frac, struct pll_parms_s *parm)
putreg32(val, PLL_DIV(reg));
/* Disable spread spectrum */
putreg32(PLL_SPREAD_SPECTRUM_ENABLE, PLL_CLR(PLL_SPREAD_SPECTRUM(reg)));
/* Set the fractional parts */
if (frac)
{
/* Disable spread spectrum */
putreg32(PLL_SPREAD_SPECTRUM_ENABLE,
PLL_CLR(PLL_SPREAD_SPECTRUM(reg)));
putreg32(PLL_NUMERATOR_MFN(parm->mfn), PLL_NUMERATOR(reg));
putreg32(PLL_DENOMINATOR_MFD(parm->mfd), PLL_DENOMINATOR(reg));
}
@ -108,6 +114,7 @@ static int pll_init(uintptr_t reg, bool frac, struct pll_parms_s *parm)
return OK;
}
#ifdef CONFIG_IMX9_CFG_PLLS
static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms_s *pfdparm)
{
uint32_t ctrl;
@ -175,6 +182,7 @@ static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms_s *pfdparm)
return OK;
}
#endif /* CONFIG_IMX9_CFG_PLLS */
#endif
static uint32_t calculate_vco_freq(const struct pll_parms_s *parm, bool frac)
@ -352,6 +360,34 @@ static uint32_t pll_pfd_freq_out(uintptr_t reg, int pfd, int div2)
return ((uint64_t)vco * 5) / (parm.mfi * 5 + parm.mfn) / div2;
}
/****************************************************************************
* Name: imx9_ccm_dram_disable_bypass
*
* Description:
* Disable clock bypass
*
* Input Parameters:
* None
*
* Returned Value:
* None
*>
****************************************************************************/
#ifdef CONFIG_IMX9_BOOTLOADER
static void imx9_dram_disable_bypass(void)
{
/* Set DRAM APB to 133Mhz */
imx9_ccm_configure_root_clock(CCM_DRAM_APB_CLK_ROOT, SYS_PLL1PFD1DIV2, 3);
/* Switch from DRAM clock root from CCM to PLL */
imx9_ccm_shared_gpr_set(CCM_SHARED_GPR_DRAM_CLK,
CCM_SHARED_GPR_DRAM_CLK_SEL_PLL);
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -369,10 +405,13 @@ static uint32_t pll_pfd_freq_out(uintptr_t reg, int pfd, int div2)
void imx9_clockconfig(void)
{
#ifdef CONFIG_IMX9_BOOTLOADER
struct imx9_pll_cfg_s pll_arm = ARMPLL_CFG;
struct imx9_pll_cfg_s pll_ddr = DRAMPLL_CFG;
#ifdef CONFIG_IMX9_CFG_PLLS
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;
#endif
/* Set the CPU clock */
@ -380,6 +419,13 @@ void imx9_clockconfig(void)
pll_init(pll_arm.reg, pll_arm.frac, &pll_arm.parms);
putreg32(CCM_GPR_A55_CLK_SEL_PLL, IMX9_CCM_GPR_SH_SET(CCM_SHARED_A55_CLK));
/* DRAM clk to 933 MHz */
pll_init(pll_ddr.reg, pll_ddr.frac, &pll_ddr.parms);
imx9_dram_disable_bypass();
#ifdef CONFIG_IMX9_CFG_PLLS
/* Run the PLL configuration */
for (i = 0; i < nitems(pll_cfgs); i++)
@ -396,6 +442,7 @@ void imx9_clockconfig(void)
pll_pfd_init(cfg->reg, cfg->pfd, &cfg->parms);
}
#endif
#endif /* CONFIG_IMX9_BOOTLOADER */
}
/****************************************************************************

View File

@ -140,7 +140,7 @@
*/
#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 DRAMPLL_CFG PLL_CFG(IMX9_DRAMPLL_BASE, true, PLL_PARMS(1, 4, 155, 1, 2))
#define PLL_CFGS \
{ \