diff mbox series

[RFC,05/13] sunxi: add support for R329 clocks

Message ID 20210722063015.421923-6-icenowy@sipeed.com
State RFC
Delegated to: Andre Przywara
Headers show
Series Add support for Allwinner R329 | expand

Commit Message

Icenowy Zheng July 22, 2021, 6:30 a.m. UTC
R329 has a quite different clock tree than other SoCs. It has only 4
PLLs and its PLL-PERIPH has two post dividers, one for the normal
PLL-PERIPH-2x output and another for a special PLL-PERIPH-800M output.
In addition, its PLL configuration registers are in PRCM memory zone,
not the ordinary CPUX CCU one.

Add support for basical R329 clock initialization.

Signed-off-by: Icenowy Zheng <icenowy@sipeed.com>
---
 arch/arm/mach-sunxi/clock_sun50i_h6.c | 49 ++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 5 deletions(-)

Comments

Samuel Holland Nov. 6, 2021, 2:59 a.m. UTC | #1
On 7/22/21 1:30 AM, Icenowy Zheng wrote:
> R329 has a quite different clock tree than other SoCs. It has only 4
> PLLs and its PLL-PERIPH has two post dividers, one for the normal
> PLL-PERIPH-2x output and another for a special PLL-PERIPH-800M output.
> In addition, its PLL configuration registers are in PRCM memory zone,
> not the ordinary CPUX CCU one.
> 
> Add support for basical R329 clock initialization.
> 
> Signed-off-by: Icenowy Zheng <icenowy@sipeed.com>

Reviewed-by: Samuel Holland <samuel@sholland.org>

One minor comment below.

> ---
>  arch/arm/mach-sunxi/clock_sun50i_h6.c | 49 ++++++++++++++++++++++++---
>  1 file changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
> index a947463e0a..28bc5fccd8 100644
> --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
> +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
> @@ -9,6 +9,13 @@ void clock_init_safe(void)
>  {
>  	struct sunxi_ccm_reg *const ccm =
>  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +#ifdef CONFIG_MACH_SUN50I_R329
> +	struct sunxi_prcm_reg *const prcm =
> +		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
> +	struct sunxi_prcm_reg *const pllccm = prcm;
> +#else
> +	struct sunxi_ccm_reg *const pllccm = ccm;
> +#endif
>  
>  	/* this seems to enable PLLs on H616 */
>  	if (IS_ENABLED(CONFIG_MACH_SUN50I_H616))
> @@ -16,22 +23,26 @@ void clock_init_safe(void)
>  
>  	clock_set_pll1(408000000);
>  
> -	writel(CCM_PLL6_DEFAULT, &ccm->pll6_cfg);
> -	while (!(readl(&ccm->pll6_cfg) & CCM_PLL6_LOCK))
> +	writel(CCM_PLL6_DEFAULT, &pllccm->pll6_cfg);
> +	while (!(readl(&pllccm->pll6_cfg) & CCM_PLL6_LOCK))
>  		;
>  
>  	clrsetbits_le32(&ccm->cpu_axi_cfg, CCM_CPU_AXI_APB_MASK | CCM_CPU_AXI_AXI_MASK,
>  			CCM_CPU_AXI_DEFAULT_FACTORS);
>  
>  	writel(CCM_PSI_AHB1_AHB2_DEFAULT, &ccm->psi_ahb1_ahb2_cfg);
> +#ifdef CCM_AHB3_DEFAULT
>  	writel(CCM_AHB3_DEFAULT, &ccm->ahb3_cfg);
> +#endif
>  	writel(CCM_APB1_DEFAULT, &ccm->apb1_cfg);
>  
> +#ifndef CONFIG_MACH_SUN50I_R329
>  	/*
>  	 * The mux and factor are set, but the clock will be enabled in
>  	 * DRAM initialization code.
>  	 */
>  	writel(MBUS_CLK_SRC_PLL6X2 | MBUS_CLK_M(3), &ccm->mbus_cfg);
> +#endif
>  }
>  #endif
>  
> @@ -60,8 +71,20 @@ void clock_set_pll1(unsigned int clk)
>  {
>  	struct sunxi_ccm_reg * const ccm =
>  		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
> +#ifdef CONFIG_MACH_SUN50I_R329
> +	struct sunxi_prcm_reg *const prcm =
> +		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
> +	struct sunxi_prcm_reg *const pllccm = prcm;
> +#else
> +	struct sunxi_ccm_reg *const pllccm = ccm;
> +#endif
>  	u32 val;
>  
> +#ifdef CONFIG_MACH_SUN50I_R329
> +	/* Fix undervoltage reset threshold */
> +	clrsetbits_le32(0x070901f4, 0xfff, 0xc0);
> +#endif
> +
>  	/* Do not support clocks < 288MHz as they need factor P */
>  	if (clk < 288000000) clk = 288000000;
>  
> @@ -73,11 +96,11 @@ void clock_set_pll1(unsigned int clk)
>  
>  	/* clk = 24*n/p, p is ignored if clock is >288MHz */
>  	writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 |
> -#ifdef CONFIG_MACH_SUN50I_H616
> +#ifndef CONFIG_MACH_SUN50I_H6
>  	       CCM_PLL1_OUT_EN |
>  #endif
> -	       CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg);
> -	while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
> +	       CCM_PLL1_CTRL_N(clk / 24000000), &pllccm->pll1_cfg);
> +	while (!(readl(&pllccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
>  
>  	/* Switch CPU to PLL1 */
>  	val = readl(&ccm->cpu_axi_cfg);
> @@ -87,6 +110,7 @@ void clock_set_pll1(unsigned int clk)
>  }
>  #endif
>  
> +#ifndef CONFIG_MACH_SUN50I_R329

The negative condition here will make it messier to add more branches in
the future, so I suggest flipping the conditional block.

>  unsigned int clock_get_pll6(void)
>  {
>  	struct sunxi_ccm_reg *const ccm =
> @@ -102,6 +126,21 @@ unsigned int clock_get_pll6(void)
>  	/* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */
>  	return 24000000 / m * n / div1 / div2;
>  }
> +#else
> +unsigned int clock_get_pll6(void)
> +{
> +	struct sunxi_prcm_reg *const prcm =
> +		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
> +
> +	uint32_t rval = readl(&prcm->pll6_cfg);
> +	int m = ((rval & CCM_PLL6_CTRL_M_MASK) >> CCM_PLL6_CTRL_M_SHIFT) + 1;
> +	int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
> +	int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
> +			CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
> +	/* The register defines PLL6-2X, not plain PLL6 */
> +	return 24000000 / m * n / div1 / 2;
> +}
> +#endif
>  
>  int clock_twi_onoff(int port, int state)
>  {
>
diff mbox series

Patch

diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
index a947463e0a..28bc5fccd8 100644
--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
@@ -9,6 +9,13 @@  void clock_init_safe(void)
 {
 	struct sunxi_ccm_reg *const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+#ifdef CONFIG_MACH_SUN50I_R329
+	struct sunxi_prcm_reg *const prcm =
+		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+	struct sunxi_prcm_reg *const pllccm = prcm;
+#else
+	struct sunxi_ccm_reg *const pllccm = ccm;
+#endif
 
 	/* this seems to enable PLLs on H616 */
 	if (IS_ENABLED(CONFIG_MACH_SUN50I_H616))
@@ -16,22 +23,26 @@  void clock_init_safe(void)
 
 	clock_set_pll1(408000000);
 
-	writel(CCM_PLL6_DEFAULT, &ccm->pll6_cfg);
-	while (!(readl(&ccm->pll6_cfg) & CCM_PLL6_LOCK))
+	writel(CCM_PLL6_DEFAULT, &pllccm->pll6_cfg);
+	while (!(readl(&pllccm->pll6_cfg) & CCM_PLL6_LOCK))
 		;
 
 	clrsetbits_le32(&ccm->cpu_axi_cfg, CCM_CPU_AXI_APB_MASK | CCM_CPU_AXI_AXI_MASK,
 			CCM_CPU_AXI_DEFAULT_FACTORS);
 
 	writel(CCM_PSI_AHB1_AHB2_DEFAULT, &ccm->psi_ahb1_ahb2_cfg);
+#ifdef CCM_AHB3_DEFAULT
 	writel(CCM_AHB3_DEFAULT, &ccm->ahb3_cfg);
+#endif
 	writel(CCM_APB1_DEFAULT, &ccm->apb1_cfg);
 
+#ifndef CONFIG_MACH_SUN50I_R329
 	/*
 	 * The mux and factor are set, but the clock will be enabled in
 	 * DRAM initialization code.
 	 */
 	writel(MBUS_CLK_SRC_PLL6X2 | MBUS_CLK_M(3), &ccm->mbus_cfg);
+#endif
 }
 #endif
 
@@ -60,8 +71,20 @@  void clock_set_pll1(unsigned int clk)
 {
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+#ifdef CONFIG_MACH_SUN50I_R329
+	struct sunxi_prcm_reg *const prcm =
+		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+	struct sunxi_prcm_reg *const pllccm = prcm;
+#else
+	struct sunxi_ccm_reg *const pllccm = ccm;
+#endif
 	u32 val;
 
+#ifdef CONFIG_MACH_SUN50I_R329
+	/* Fix undervoltage reset threshold */
+	clrsetbits_le32(0x070901f4, 0xfff, 0xc0);
+#endif
+
 	/* Do not support clocks < 288MHz as they need factor P */
 	if (clk < 288000000) clk = 288000000;
 
@@ -73,11 +96,11 @@  void clock_set_pll1(unsigned int clk)
 
 	/* clk = 24*n/p, p is ignored if clock is >288MHz */
 	writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 |
-#ifdef CONFIG_MACH_SUN50I_H616
+#ifndef CONFIG_MACH_SUN50I_H6
 	       CCM_PLL1_OUT_EN |
 #endif
-	       CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg);
-	while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
+	       CCM_PLL1_CTRL_N(clk / 24000000), &pllccm->pll1_cfg);
+	while (!(readl(&pllccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
 
 	/* Switch CPU to PLL1 */
 	val = readl(&ccm->cpu_axi_cfg);
@@ -87,6 +110,7 @@  void clock_set_pll1(unsigned int clk)
 }
 #endif
 
+#ifndef CONFIG_MACH_SUN50I_R329
 unsigned int clock_get_pll6(void)
 {
 	struct sunxi_ccm_reg *const ccm =
@@ -102,6 +126,21 @@  unsigned int clock_get_pll6(void)
 	/* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */
 	return 24000000 / m * n / div1 / div2;
 }
+#else
+unsigned int clock_get_pll6(void)
+{
+	struct sunxi_prcm_reg *const prcm =
+		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+
+	uint32_t rval = readl(&prcm->pll6_cfg);
+	int m = ((rval & CCM_PLL6_CTRL_M_MASK) >> CCM_PLL6_CTRL_M_SHIFT) + 1;
+	int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
+	int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
+			CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
+	/* The register defines PLL6-2X, not plain PLL6 */
+	return 24000000 / m * n / div1 / 2;
+}
+#endif
 
 int clock_twi_onoff(int port, int state)
 {