diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index 5d6519d2367..5881ab88573 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -13,6 +13,7 @@ #include #endif +/* Main CCU register offsets */ #define CCU_H6_PLL1_CFG 0x000 #define CCU_H6_PLL5_CFG 0x010 #define CCU_H6_PLL6_CFG 0x020 @@ -31,6 +32,14 @@ #define CCU_H6_UART_GATE_RESET 0x90c #define CCU_H6_I2C_GATE_RESET 0x91c +/* A523 CPU PLL offsets */ +#define CPC_CPUA_PLL_CTRL 0x04 +#define CPC_DSU_PLL_CTRL 0x08 +#define CPC_CPUB_PLL_CTRL 0x0c +#define CPC_CPUA_CLK_REG 0x60 +#define CPC_CPUB_CLK_REG 0x64 +#define CPC_DSU_CLK_REG 0x6c + /* PLL bit fields */ #define CCM_PLL_CTRL_EN BIT(31) #define CCM_PLL_LDO_EN BIT(30) @@ -42,6 +51,14 @@ #define CCM_PLL1_CTRL_N_MASK GENMASK(15, 8) #define CCM_PLL1_CTRL_N(n) (((n) - 1) << 8) +/* A523 CPU clock fields */ +#define CPU_CLK_SRC_HOSC (0 << 24) +#define CPU_CLK_SRC_CPUPLL (3 << 24) +#define CPU_CLK_CTRL_P(p) ((p) << 16) +#define CPU_CLK_APB_DIV(n) (((n) - 1) << 8) +#define CPU_CLK_PERI_DIV(m1) (((m1) - 1) << 2) +#define CPU_CLK_AXI_DIV(m) (((m) - 1) << 0) + /* pll5 bit field */ #define CCM_PLL5_CTRL_N(n) (((n) - 1) << 8) #define CCM_PLL5_CTRL_DIV1(div1) ((div1) << 0) diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h index 908a582ae0f..c04ddb3f1d4 100644 --- a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h +++ b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h @@ -30,6 +30,8 @@ #define SUNXI_CPUCFG_BASE 0x09010000 +#define SUNXI_CPU_PLL_CFG_BASE 0x08817000 + #ifndef __ASSEMBLY__ void sunxi_board_init(void); void sunxi_reset(void); diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 84064c4ed86..3a4399a9c6c 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -6,6 +6,10 @@ #include #include +#ifndef SUNXI_CPU_PLL_CFG_BASE +#define SUNXI_CPU_PLL_CFG_BASE 0 +#endif + #ifdef CONFIG_XPL_BUILD void clock_init_safe(void) { @@ -120,6 +124,37 @@ static void clock_set_pll(u32 *reg, unsigned int n) } } +/* Program the PLLs for both clusters plus the DSU. */ +static void clock_a523_set_cpu_plls(unsigned int n_factor) +{ + void *const cpc = (void *)SUNXI_CPU_PLL_CFG_BASE; + u32 val; + + val = CPU_CLK_SRC_HOSC | CPU_CLK_CTRL_P(0) | + CPU_CLK_APB_DIV(4) | CPU_CLK_PERI_DIV(2) | + CPU_CLK_AXI_DIV(2); + + /* Switch CPU clock source to 24MHz HOSC while changing the PLL */ + writel(val, cpc + CPC_CPUA_CLK_REG); + writel(val, cpc + CPC_CPUB_CLK_REG); + udelay(20); + writel(CPU_CLK_SRC_HOSC | CPU_CLK_CTRL_P(0), + cpc + CPC_DSU_CLK_REG); + udelay(20); + + clock_set_pll(cpc + CPC_CPUA_PLL_CTRL, n_factor); + clock_set_pll(cpc + CPC_CPUB_PLL_CTRL, n_factor); + clock_set_pll(cpc + CPC_DSU_PLL_CTRL, n_factor); + + /* Switch CPU clock source to the CPU PLL */ + clrsetbits_le32(cpc + CPC_CPUA_CLK_REG, CPU_CLK_SRC_HOSC, + CPU_CLK_SRC_CPUPLL); + clrsetbits_le32(cpc + CPC_CPUB_CLK_REG, CPU_CLK_SRC_HOSC, + CPU_CLK_SRC_CPUPLL); + clrsetbits_le32(cpc + CPC_DSU_CLK_REG, CPU_CLK_SRC_HOSC, + CPU_CLK_SRC_CPUPLL); +} + static void clock_h6_set_cpu_pll(unsigned int n_factor) { void *const ccm = (void *)SUNXI_CCM_BASE; @@ -148,7 +183,10 @@ void clock_set_pll1(unsigned int clk) clk /= 24000000; - clock_h6_set_cpu_pll(clk); + if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) + clock_a523_set_cpu_plls(clk); + else + clock_h6_set_cpu_pll(clk); } int clock_twi_onoff(int port, int state)