summaryrefslogtreecommitdiff
path: root/arch/mips/ath79/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/ath79/clock.c')
-rw-r--r--arch/mips/ath79/clock.c593
1 files changed, 408 insertions, 185 deletions
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c
index 765ef30e3e1c..050f6553f398 100644
--- a/arch/mips/ath79/clock.c
+++ b/arch/mips/ath79/clock.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Atheros AR71XX/AR724X/AR913X common routines
*
@@ -5,17 +6,18 @@
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
*
* Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/ath79-clk.h>
#include <asm/div64.h>
@@ -24,148 +26,187 @@
#include "common.h"
#define AR71XX_BASE_FREQ 40000000
-#define AR724X_BASE_FREQ 5000000
-#define AR913X_BASE_FREQ 5000000
+#define AR724X_BASE_FREQ 40000000
-struct clk {
- unsigned long rate;
+static struct clk *clks[ATH79_CLK_END];
+static struct clk_onecell_data clk_data = {
+ .clks = clks,
+ .clk_num = ARRAY_SIZE(clks),
};
-static struct clk ath79_ref_clk;
-static struct clk ath79_cpu_clk;
-static struct clk ath79_ddr_clk;
-static struct clk ath79_ahb_clk;
-static struct clk ath79_wdt_clk;
-static struct clk ath79_uart_clk;
+static const char * const clk_names[ATH79_CLK_END] = {
+ [ATH79_CLK_CPU] = "cpu",
+ [ATH79_CLK_DDR] = "ddr",
+ [ATH79_CLK_AHB] = "ahb",
+ [ATH79_CLK_REF] = "ref",
+ [ATH79_CLK_MDIO] = "mdio",
+};
-static void __init ar71xx_clocks_init(void)
+static const char * __init ath79_clk_name(int type)
{
- u32 pll;
- u32 freq;
- u32 div;
+ BUG_ON(type >= ARRAY_SIZE(clk_names) || !clk_names[type]);
+ return clk_names[type];
+}
- ath79_ref_clk.rate = AR71XX_BASE_FREQ;
+static void __init __ath79_set_clk(int type, const char *name, struct clk *clk)
+{
+ if (IS_ERR(clk))
+ panic("failed to allocate %s clock structure", clk_names[type]);
- pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
+ clks[type] = clk;
+ clk_register_clkdev(clk, name, NULL);
+}
- div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
- freq = div * ath79_ref_clk.rate;
+static struct clk * __init ath79_set_clk(int type, unsigned long rate)
+{
+ const char *name = ath79_clk_name(type);
+ struct clk *clk;
- div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
- ath79_cpu_clk.rate = freq / div;
+ clk = clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+ __ath79_set_clk(type, name, clk);
+ return clk;
+}
- div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
- ath79_ddr_clk.rate = freq / div;
+static struct clk * __init ath79_set_ff_clk(int type, const char *parent,
+ unsigned int mult, unsigned int div)
+{
+ const char *name = ath79_clk_name(type);
+ struct clk *clk;
- div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
- ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+ clk = clk_register_fixed_factor(NULL, name, parent, 0, mult, div);
+ __ath79_set_clk(type, name, clk);
+ return clk;
+}
+
+static unsigned long __init ath79_setup_ref_clk(unsigned long rate)
+{
+ struct clk *clk = clks[ATH79_CLK_REF];
+
+ if (clk)
+ rate = clk_get_rate(clk);
+ else
+ clk = ath79_set_clk(ATH79_CLK_REF, rate);
- ath79_wdt_clk.rate = ath79_ahb_clk.rate;
- ath79_uart_clk.rate = ath79_ahb_clk.rate;
+ return rate;
}
-static void __init ar724x_clocks_init(void)
+static void __init ar71xx_clocks_init(void __iomem *pll_base)
{
+ unsigned long ref_rate;
+ unsigned long cpu_rate;
+ unsigned long ddr_rate;
+ unsigned long ahb_rate;
u32 pll;
u32 freq;
u32 div;
- ath79_ref_clk.rate = AR724X_BASE_FREQ;
- pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
+ ref_rate = ath79_setup_ref_clk(AR71XX_BASE_FREQ);
- div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
- freq = div * ath79_ref_clk.rate;
+ pll = __raw_readl(pll_base + AR71XX_PLL_REG_CPU_CONFIG);
- div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
- freq *= div;
+ div = ((pll >> AR71XX_PLL_FB_SHIFT) & AR71XX_PLL_FB_MASK) + 1;
+ freq = div * ref_rate;
- ath79_cpu_clk.rate = freq;
+ div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
+ cpu_rate = freq / div;
- div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
- ath79_ddr_clk.rate = freq / div;
+ div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
+ ddr_rate = freq / div;
- div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
- ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+ div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
+ ahb_rate = cpu_rate / div;
- ath79_wdt_clk.rate = ath79_ahb_clk.rate;
- ath79_uart_clk.rate = ath79_ahb_clk.rate;
+ ath79_set_clk(ATH79_CLK_CPU, cpu_rate);
+ ath79_set_clk(ATH79_CLK_DDR, ddr_rate);
+ ath79_set_clk(ATH79_CLK_AHB, ahb_rate);
}
-static void __init ar913x_clocks_init(void)
+static void __init ar724x_clocks_init(void __iomem *pll_base)
{
+ u32 mult, div, ddr_div, ahb_div;
u32 pll;
- u32 freq;
- u32 div;
- ath79_ref_clk.rate = AR913X_BASE_FREQ;
- pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
+ ath79_setup_ref_clk(AR71XX_BASE_FREQ);
- div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
- freq = div * ath79_ref_clk.rate;
+ pll = __raw_readl(pll_base + AR724X_PLL_REG_CPU_CONFIG);
- ath79_cpu_clk.rate = freq;
+ mult = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK);
+ div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK) * 2;
- div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
- ath79_ddr_clk.rate = freq / div;
+ ddr_div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
+ ahb_div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
- div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
- ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
-
- ath79_wdt_clk.rate = ath79_ahb_clk.rate;
- ath79_uart_clk.rate = ath79_ahb_clk.rate;
+ ath79_set_ff_clk(ATH79_CLK_CPU, "ref", mult, div);
+ ath79_set_ff_clk(ATH79_CLK_DDR, "ref", mult, div * ddr_div);
+ ath79_set_ff_clk(ATH79_CLK_AHB, "ref", mult, div * ahb_div);
}
-static void __init ar933x_clocks_init(void)
+static void __init ar933x_clocks_init(void __iomem *pll_base)
{
+ unsigned long ref_rate;
u32 clock_ctrl;
- u32 cpu_config;
- u32 freq;
+ u32 ref_div;
+ u32 ninit_mul;
+ u32 out_div;
+
+ u32 cpu_div;
+ u32 ddr_div;
+ u32 ahb_div;
u32 t;
t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
if (t & AR933X_BOOTSTRAP_REF_CLK_40)
- ath79_ref_clk.rate = (40 * 1000 * 1000);
+ ref_rate = (40 * 1000 * 1000);
else
- ath79_ref_clk.rate = (25 * 1000 * 1000);
+ ref_rate = (25 * 1000 * 1000);
- clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG);
+ ath79_setup_ref_clk(ref_rate);
+
+ clock_ctrl = __raw_readl(pll_base + AR933X_PLL_CLOCK_CTRL_REG);
if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
- ath79_cpu_clk.rate = ath79_ref_clk.rate;
- ath79_ahb_clk.rate = ath79_ref_clk.rate;
- ath79_ddr_clk.rate = ath79_ref_clk.rate;
+ ref_div = 1;
+ ninit_mul = 1;
+ out_div = 1;
+
+ cpu_div = 1;
+ ddr_div = 1;
+ ahb_div = 1;
} else {
- cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG);
+ u32 cpu_config;
+ u32 t;
+
+ cpu_config = __raw_readl(pll_base + AR933X_PLL_CPU_CONFIG_REG);
t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
- freq = ath79_ref_clk.rate / t;
+ ref_div = t;
- t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
+ ninit_mul = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
AR933X_PLL_CPU_CONFIG_NINT_MASK;
- freq *= t;
t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
if (t == 0)
t = 1;
- freq >>= t;
+ out_div = (1 << t);
- t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
+ cpu_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1;
- ath79_cpu_clk.rate = freq / t;
- t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
+ ddr_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1;
- ath79_ddr_clk.rate = freq / t;
- t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
+ ahb_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1;
- ath79_ahb_clk.rate = freq / t;
}
- ath79_wdt_clk.rate = ath79_ref_clk.rate;
- ath79_uart_clk.rate = ath79_ref_clk.rate;
+ ath79_set_ff_clk(ATH79_CLK_CPU, "ref", ninit_mul,
+ ref_div * out_div * cpu_div);
+ ath79_set_ff_clk(ATH79_CLK_DDR, "ref", ninit_mul,
+ ref_div * out_div * ddr_div);
+ ath79_set_ff_clk(ATH79_CLK_AHB, "ref", ninit_mul,
+ ref_div * out_div * ahb_div);
}
static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
@@ -174,12 +215,12 @@ static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
u64 t;
u32 ret;
- t = ath79_ref_clk.rate;
+ t = ref;
t *= nint;
do_div(t, ref_div);
ret = t;
- t = ath79_ref_clk.rate;
+ t = ref;
t *= nfrac;
do_div(t, ref_div * frac);
ret += t;
@@ -188,8 +229,12 @@ static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
return ret;
}
-static void __init ar934x_clocks_init(void)
+static void __init ar934x_clocks_init(void __iomem *pll_base)
{
+ unsigned long ref_rate;
+ unsigned long cpu_rate;
+ unsigned long ddr_rate;
+ unsigned long ahb_rate;
u32 pll, out_div, ref_div, nint, nfrac, frac, clk_ctrl, postdiv;
u32 cpu_pll, ddr_pll;
u32 bootstrap;
@@ -199,9 +244,11 @@ static void __init ar934x_clocks_init(void)
bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40)
- ath79_ref_clk.rate = 40 * 1000 * 1000;
+ ref_rate = 40 * 1000 * 1000;
else
- ath79_ref_clk.rate = 25 * 1000 * 1000;
+ ref_rate = 25 * 1000 * 1000;
+
+ ref_rate = ath79_setup_ref_clk(ref_rate);
pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL2_REG);
if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
@@ -215,7 +262,7 @@ static void __init ar934x_clocks_init(void)
AR934X_SRIF_DPLL1_REFDIV_MASK;
frac = 1 << 18;
} else {
- pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG);
+ pll = __raw_readl(pll_base + AR934X_PLL_CPU_CONFIG_REG);
out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
@@ -227,7 +274,7 @@ static void __init ar934x_clocks_init(void)
frac = 1 << 6;
}
- cpu_pll = ar934x_get_pll_freq(ath79_ref_clk.rate, ref_div, nint,
+ cpu_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
nfrac, frac, out_div);
pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL2_REG);
@@ -242,7 +289,7 @@ static void __init ar934x_clocks_init(void)
AR934X_SRIF_DPLL1_REFDIV_MASK;
frac = 1 << 18;
} else {
- pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG);
+ pll = __raw_readl(pll_base + AR934X_PLL_DDR_CONFIG_REG);
out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
@@ -254,60 +301,154 @@ static void __init ar934x_clocks_init(void)
frac = 1 << 10;
}
- ddr_pll = ar934x_get_pll_freq(ath79_ref_clk.rate, ref_div, nint,
+ ddr_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
nfrac, frac, out_div);
- clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
+ clk_ctrl = __raw_readl(pll_base + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) &
AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK;
if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS)
- ath79_cpu_clk.rate = ath79_ref_clk.rate;
+ cpu_rate = ref_rate;
else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL)
- ath79_cpu_clk.rate = cpu_pll / (postdiv + 1);
+ cpu_rate = cpu_pll / (postdiv + 1);
else
- ath79_cpu_clk.rate = ddr_pll / (postdiv + 1);
+ cpu_rate = ddr_pll / (postdiv + 1);
postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) &
AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK;
if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS)
- ath79_ddr_clk.rate = ath79_ref_clk.rate;
+ ddr_rate = ref_rate;
else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL)
- ath79_ddr_clk.rate = ddr_pll / (postdiv + 1);
+ ddr_rate = ddr_pll / (postdiv + 1);
else
- ath79_ddr_clk.rate = cpu_pll / (postdiv + 1);
+ ddr_rate = cpu_pll / (postdiv + 1);
postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) &
AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK;
if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS)
- ath79_ahb_clk.rate = ath79_ref_clk.rate;
+ ahb_rate = ref_rate;
else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL)
- ath79_ahb_clk.rate = ddr_pll / (postdiv + 1);
+ ahb_rate = ddr_pll / (postdiv + 1);
else
- ath79_ahb_clk.rate = cpu_pll / (postdiv + 1);
+ ahb_rate = cpu_pll / (postdiv + 1);
+
+ ath79_set_clk(ATH79_CLK_CPU, cpu_rate);
+ ath79_set_clk(ATH79_CLK_DDR, ddr_rate);
+ ath79_set_clk(ATH79_CLK_AHB, ahb_rate);
- ath79_wdt_clk.rate = ath79_ref_clk.rate;
- ath79_uart_clk.rate = ath79_ref_clk.rate;
+ clk_ctrl = __raw_readl(pll_base + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+ if (clk_ctrl & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL)
+ ath79_set_clk(ATH79_CLK_MDIO, 100 * 1000 * 1000);
iounmap(dpll_base);
}
-static void __init qca955x_clocks_init(void)
+static void __init qca953x_clocks_init(void __iomem *pll_base)
{
+ unsigned long ref_rate;
+ unsigned long cpu_rate;
+ unsigned long ddr_rate;
+ unsigned long ahb_rate;
+ u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
+ u32 cpu_pll, ddr_pll;
+ u32 bootstrap;
+
+ bootstrap = ath79_reset_rr(QCA953X_RESET_REG_BOOTSTRAP);
+ if (bootstrap & QCA953X_BOOTSTRAP_REF_CLK_40)
+ ref_rate = 40 * 1000 * 1000;
+ else
+ ref_rate = 25 * 1000 * 1000;
+
+ ref_rate = ath79_setup_ref_clk(ref_rate);
+
+ pll = __raw_readl(pll_base + QCA953X_PLL_CPU_CONFIG_REG);
+ out_div = (pll >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+ QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK;
+ ref_div = (pll >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+ QCA953X_PLL_CPU_CONFIG_REFDIV_MASK;
+ nint = (pll >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT) &
+ QCA953X_PLL_CPU_CONFIG_NINT_MASK;
+ frac = (pll >> QCA953X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
+ QCA953X_PLL_CPU_CONFIG_NFRAC_MASK;
+
+ cpu_pll = nint * ref_rate / ref_div;
+ cpu_pll += frac * (ref_rate >> 6) / ref_div;
+ cpu_pll /= (1 << out_div);
+
+ pll = __raw_readl(pll_base + QCA953X_PLL_DDR_CONFIG_REG);
+ out_div = (pll >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
+ QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK;
+ ref_div = (pll >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
+ QCA953X_PLL_DDR_CONFIG_REFDIV_MASK;
+ nint = (pll >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT) &
+ QCA953X_PLL_DDR_CONFIG_NINT_MASK;
+ frac = (pll >> QCA953X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
+ QCA953X_PLL_DDR_CONFIG_NFRAC_MASK;
+
+ ddr_pll = nint * ref_rate / ref_div;
+ ddr_pll += frac * (ref_rate >> 6) / (ref_div << 4);
+ ddr_pll /= (1 << out_div);
+
+ clk_ctrl = __raw_readl(pll_base + QCA953X_PLL_CLK_CTRL_REG);
+
+ postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
+ QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
+
+ if (clk_ctrl & QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
+ cpu_rate = ref_rate;
+ else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
+ cpu_rate = cpu_pll / (postdiv + 1);
+ else
+ cpu_rate = ddr_pll / (postdiv + 1);
+
+ postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
+ QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
+
+ if (clk_ctrl & QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
+ ddr_rate = ref_rate;
+ else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
+ ddr_rate = ddr_pll / (postdiv + 1);
+ else
+ ddr_rate = cpu_pll / (postdiv + 1);
+
+ postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
+ QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
+
+ if (clk_ctrl & QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+ ahb_rate = ref_rate;
+ else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
+ ahb_rate = ddr_pll / (postdiv + 1);
+ else
+ ahb_rate = cpu_pll / (postdiv + 1);
+
+ ath79_set_clk(ATH79_CLK_CPU, cpu_rate);
+ ath79_set_clk(ATH79_CLK_DDR, ddr_rate);
+ ath79_set_clk(ATH79_CLK_AHB, ahb_rate);
+}
+
+static void __init qca955x_clocks_init(void __iomem *pll_base)
+{
+ unsigned long ref_rate;
+ unsigned long cpu_rate;
+ unsigned long ddr_rate;
+ unsigned long ahb_rate;
u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
u32 cpu_pll, ddr_pll;
u32 bootstrap;
bootstrap = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP);
if (bootstrap & QCA955X_BOOTSTRAP_REF_CLK_40)
- ath79_ref_clk.rate = 40 * 1000 * 1000;
+ ref_rate = 40 * 1000 * 1000;
else
- ath79_ref_clk.rate = 25 * 1000 * 1000;
+ ref_rate = 25 * 1000 * 1000;
+
+ ref_rate = ath79_setup_ref_clk(ref_rate);
- pll = ath79_pll_rr(QCA955X_PLL_CPU_CONFIG_REG);
+ pll = __raw_readl(pll_base + QCA955X_PLL_CPU_CONFIG_REG);
out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK;
ref_div = (pll >> QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
@@ -317,11 +458,11 @@ static void __init qca955x_clocks_init(void)
frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
QCA955X_PLL_CPU_CONFIG_NFRAC_MASK;
- cpu_pll = nint * ath79_ref_clk.rate / ref_div;
- cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 6));
+ cpu_pll = nint * ref_rate / ref_div;
+ cpu_pll += frac * ref_rate / (ref_div * (1 << 6));
cpu_pll /= (1 << out_div);
- pll = ath79_pll_rr(QCA955X_PLL_DDR_CONFIG_REG);
+ pll = __raw_readl(pll_base + QCA955X_PLL_DDR_CONFIG_REG);
out_div = (pll >> QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK;
ref_div = (pll >> QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
@@ -331,120 +472,202 @@ static void __init qca955x_clocks_init(void)
frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
QCA955X_PLL_DDR_CONFIG_NFRAC_MASK;
- ddr_pll = nint * ath79_ref_clk.rate / ref_div;
- ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 10));
+ ddr_pll = nint * ref_rate / ref_div;
+ ddr_pll += frac * ref_rate / (ref_div * (1 << 10));
ddr_pll /= (1 << out_div);
- clk_ctrl = ath79_pll_rr(QCA955X_PLL_CLK_CTRL_REG);
+ clk_ctrl = __raw_readl(pll_base + QCA955X_PLL_CLK_CTRL_REG);
postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
- ath79_cpu_clk.rate = ath79_ref_clk.rate;
+ cpu_rate = ref_rate;
else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
- ath79_cpu_clk.rate = ddr_pll / (postdiv + 1);
+ cpu_rate = ddr_pll / (postdiv + 1);
else
- ath79_cpu_clk.rate = cpu_pll / (postdiv + 1);
+ cpu_rate = cpu_pll / (postdiv + 1);
postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
- ath79_ddr_clk.rate = ath79_ref_clk.rate;
+ ddr_rate = ref_rate;
else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
- ath79_ddr_clk.rate = cpu_pll / (postdiv + 1);
+ ddr_rate = cpu_pll / (postdiv + 1);
else
- ath79_ddr_clk.rate = ddr_pll / (postdiv + 1);
+ ddr_rate = ddr_pll / (postdiv + 1);
postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
- ath79_ahb_clk.rate = ath79_ref_clk.rate;
+ ahb_rate = ref_rate;
else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
- ath79_ahb_clk.rate = ddr_pll / (postdiv + 1);
+ ahb_rate = ddr_pll / (postdiv + 1);
else
- ath79_ahb_clk.rate = cpu_pll / (postdiv + 1);
+ ahb_rate = cpu_pll / (postdiv + 1);
- ath79_wdt_clk.rate = ath79_ref_clk.rate;
- ath79_uart_clk.rate = ath79_ref_clk.rate;
+ ath79_set_clk(ATH79_CLK_CPU, cpu_rate);
+ ath79_set_clk(ATH79_CLK_DDR, ddr_rate);
+ ath79_set_clk(ATH79_CLK_AHB, ahb_rate);
}
-void __init ath79_clocks_init(void)
+static void __init qca956x_clocks_init(void __iomem *pll_base)
{
- if (soc_is_ar71xx())
- ar71xx_clocks_init();
- else if (soc_is_ar724x())
- ar724x_clocks_init();
- else if (soc_is_ar913x())
- ar913x_clocks_init();
- else if (soc_is_ar933x())
- ar933x_clocks_init();
- else if (soc_is_ar934x())
- ar934x_clocks_init();
- else if (soc_is_qca955x())
- qca955x_clocks_init();
+ unsigned long ref_rate;
+ unsigned long cpu_rate;
+ unsigned long ddr_rate;
+ unsigned long ahb_rate;
+ u32 pll, out_div, ref_div, nint, hfrac, lfrac, clk_ctrl, postdiv;
+ u32 cpu_pll, ddr_pll;
+ u32 bootstrap;
+
+ /*
+ * QCA956x timer init workaround has to be applied right before setting
+ * up the clock. Else, there will be no jiffies
+ */
+ u32 misc;
+
+ misc = ath79_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE);
+ misc |= MISC_INT_MIPS_SI_TIMERINT_MASK;
+ ath79_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, misc);
+
+ bootstrap = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
+ if (bootstrap & QCA956X_BOOTSTRAP_REF_CLK_40)
+ ref_rate = 40 * 1000 * 1000;
else
- BUG();
-
- pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
- "Ref:%lu.%03luMHz",
- ath79_cpu_clk.rate / 1000000,
- (ath79_cpu_clk.rate / 1000) % 1000,
- ath79_ddr_clk.rate / 1000000,
- (ath79_ddr_clk.rate / 1000) % 1000,
- ath79_ahb_clk.rate / 1000000,
- (ath79_ahb_clk.rate / 1000) % 1000,
- ath79_ref_clk.rate / 1000000,
- (ath79_ref_clk.rate / 1000) % 1000);
-}
+ ref_rate = 25 * 1000 * 1000;
+
+ ref_rate = ath79_setup_ref_clk(ref_rate);
+
+ pll = __raw_readl(pll_base + QCA956X_PLL_CPU_CONFIG_REG);
+ out_div = (pll >> QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+ QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK;
+ ref_div = (pll >> QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+ QCA956X_PLL_CPU_CONFIG_REFDIV_MASK;
+
+ pll = __raw_readl(pll_base + QCA956X_PLL_CPU_CONFIG1_REG);
+ nint = (pll >> QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT) &
+ QCA956X_PLL_CPU_CONFIG1_NINT_MASK;
+ hfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT) &
+ QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK;
+ lfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT) &
+ QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK;
+
+ cpu_pll = nint * ref_rate / ref_div;
+ cpu_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
+ cpu_pll += (hfrac >> 13) * ref_rate / ref_div;
+ cpu_pll /= (1 << out_div);
-/*
- * Linux clock API
- */
-struct clk *clk_get(struct device *dev, const char *id)
-{
- if (!strcmp(id, "ref"))
- return &ath79_ref_clk;
+ pll = __raw_readl(pll_base + QCA956X_PLL_DDR_CONFIG_REG);
+ out_div = (pll >> QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
+ QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK;
+ ref_div = (pll >> QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
+ QCA956X_PLL_DDR_CONFIG_REFDIV_MASK;
+ pll = __raw_readl(pll_base + QCA956X_PLL_DDR_CONFIG1_REG);
+ nint = (pll >> QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT) &
+ QCA956X_PLL_DDR_CONFIG1_NINT_MASK;
+ hfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT) &
+ QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK;
+ lfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT) &
+ QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK;
+
+ ddr_pll = nint * ref_rate / ref_div;
+ ddr_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
+ ddr_pll += (hfrac >> 13) * ref_rate / ref_div;
+ ddr_pll /= (1 << out_div);
- if (!strcmp(id, "cpu"))
- return &ath79_cpu_clk;
+ clk_ctrl = __raw_readl(pll_base + QCA956X_PLL_CLK_CTRL_REG);
- if (!strcmp(id, "ddr"))
- return &ath79_ddr_clk;
+ postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
+ QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
- if (!strcmp(id, "ahb"))
- return &ath79_ahb_clk;
+ if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
+ cpu_rate = ref_rate;
+ else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL)
+ cpu_rate = ddr_pll / (postdiv + 1);
+ else
+ cpu_rate = cpu_pll / (postdiv + 1);
- if (!strcmp(id, "wdt"))
- return &ath79_wdt_clk;
+ postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
+ QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
- if (!strcmp(id, "uart"))
- return &ath79_uart_clk;
+ if (clk_ctrl & QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
+ ddr_rate = ref_rate;
+ else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL)
+ ddr_rate = cpu_pll / (postdiv + 1);
+ else
+ ddr_rate = ddr_pll / (postdiv + 1);
- return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
+ postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
+ QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
-int clk_enable(struct clk *clk)
-{
- return 0;
-}
-EXPORT_SYMBOL(clk_enable);
+ if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+ ahb_rate = ref_rate;
+ else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
+ ahb_rate = ddr_pll / (postdiv + 1);
+ else
+ ahb_rate = cpu_pll / (postdiv + 1);
-void clk_disable(struct clk *clk)
-{
+ ath79_set_clk(ATH79_CLK_CPU, cpu_rate);
+ ath79_set_clk(ATH79_CLK_DDR, ddr_rate);
+ ath79_set_clk(ATH79_CLK_AHB, ahb_rate);
}
-EXPORT_SYMBOL(clk_disable);
-unsigned long clk_get_rate(struct clk *clk)
+static void __init ath79_clocks_init_dt(struct device_node *np)
{
- return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
+ struct clk *ref_clk;
+ void __iomem *pll_base;
-void clk_put(struct clk *clk)
-{
+ ref_clk = of_clk_get(np, 0);
+ if (!IS_ERR(ref_clk))
+ clks[ATH79_CLK_REF] = ref_clk;
+
+ pll_base = of_iomap(np, 0);
+ if (!pll_base) {
+ pr_err("%pOF: can't map pll registers\n", np);
+ goto err_clk;
+ }
+
+ if (of_device_is_compatible(np, "qca,ar7100-pll"))
+ ar71xx_clocks_init(pll_base);
+ else if (of_device_is_compatible(np, "qca,ar7240-pll") ||
+ of_device_is_compatible(np, "qca,ar9130-pll"))
+ ar724x_clocks_init(pll_base);
+ else if (of_device_is_compatible(np, "qca,ar9330-pll"))
+ ar933x_clocks_init(pll_base);
+ else if (of_device_is_compatible(np, "qca,ar9340-pll"))
+ ar934x_clocks_init(pll_base);
+ else if (of_device_is_compatible(np, "qca,qca9530-pll"))
+ qca953x_clocks_init(pll_base);
+ else if (of_device_is_compatible(np, "qca,qca9550-pll"))
+ qca955x_clocks_init(pll_base);
+ else if (of_device_is_compatible(np, "qca,qca9560-pll"))
+ qca956x_clocks_init(pll_base);
+
+ if (!clks[ATH79_CLK_MDIO])
+ clks[ATH79_CLK_MDIO] = clks[ATH79_CLK_REF];
+
+ if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) {
+ pr_err("%pOF: could not register clk provider\n", np);
+ goto err_iounmap;
+ }
+
+ return;
+
+err_iounmap:
+ iounmap(pll_base);
+
+err_clk:
+ clk_put(ref_clk);
}
-EXPORT_SYMBOL(clk_put);
+
+CLK_OF_DECLARE(ar7100_clk, "qca,ar7100-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar7240_clk, "qca,ar7240-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar9130_clk, "qca,ar9130-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar9330_clk, "qca,ar9330-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar9340_clk, "qca,ar9340-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar9530_clk, "qca,qca9530-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar9550_clk, "qca,qca9550-pll", ath79_clocks_init_dt);
+CLK_OF_DECLARE(ar9560_clk, "qca,qca9560-pll", ath79_clocks_init_dt);