* [PATCH v2 2/6] MIPS: ath79: move the bootstrap reference clock to setup
2026-11-10 1:36 [PATCH v2 0/6] clk: add a driver for the ath79 PLL controller Rosen Penev
2026-11-10 1:36 ` [PATCH v2 1/6] MIPS: ath79: apply the QCA956x timer workaround in setup Rosen Penev
@ 2026-11-10 1:36 ` Rosen Penev
2026-11-10 1:36 ` [PATCH v2 3/6] dt-bindings: clock: ath79: add the UART1 clock Rosen Penev
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rosen Penev @ 2026-11-10 1:36 UTC (permalink / raw)
To: Thomas Bogendoerfer, Stephen Boyd, Brian Masney, Jerome Brunet,
Alban Bedel, Antony Pavlov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, linux-mips, linux-clk, devicetree
The qca,ath79-pll binding requires the reference clock as an input, and a
rate in the device tree already took precedence over the 25/40 MHz that
the clock code read from the bootstrap pins. Many AR933x boards leave the
rate out, though, and rely on the pins.
Read the pins in plat_time_init() instead, and register the reference
clock from them only when the device tree gives no rate. The clock code
then takes the DT clock or this one through the clk API and no longer
needs ath79_reset_base. When the device tree does give a rate, warn if
it disagrees with the pins: a wrong rate leaves the CPU, DDR and AHB rates
off, the UART baud rate included.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
arch/mips/ath79/clock.c | 71 ++++++++-------------------------
arch/mips/ath79/setup.c | 87 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+), 54 deletions(-)
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c
index 8c5eaa4ab6e0..85f747cf37a8 100644
--- a/arch/mips/ath79/clock.c
+++ b/arch/mips/ath79/clock.c
@@ -25,9 +25,6 @@
#include <asm/mach-ath79/ar71xx_regs.h>
#include "common.h"
-#define AR71XX_BASE_FREQ 40000000
-#define AR724X_BASE_FREQ 40000000
-
static struct clk *clks[ATH79_CLK_END];
static struct clk_onecell_data clk_data = {
.clks = clks,
@@ -78,16 +75,12 @@ static struct clk * __init ath79_set_ff_clk(int type, const char *parent,
return clk;
}
-static unsigned long __init ath79_setup_ref_clk(unsigned long rate)
+static unsigned long __init ath79_get_ref_rate(void)
{
- struct clk *clk = clks[ATH79_CLK_REF];
-
- if (clk)
- rate = clk_get_rate(clk);
- else
- clk = ath79_set_clk(ATH79_CLK_REF, rate);
+ if (!clks[ATH79_CLK_REF])
+ panic("ath79: no reference clock");
- return rate;
+ return clk_get_rate(clks[ATH79_CLK_REF]);
}
static void __init ar71xx_clocks_init(void __iomem *pll_base)
@@ -100,7 +93,7 @@ static void __init ar71xx_clocks_init(void __iomem *pll_base)
u32 freq;
u32 div;
- ref_rate = ath79_setup_ref_clk(AR71XX_BASE_FREQ);
+ ref_rate = ath79_get_ref_rate();
pll = __raw_readl(pll_base + AR71XX_PLL_REG_CPU_CONFIG);
@@ -126,7 +119,7 @@ static void __init ar724x_clocks_init(void __iomem *pll_base)
u32 mult, div, ddr_div, ahb_div;
u32 pll;
- ath79_setup_ref_clk(AR71XX_BASE_FREQ);
+ ath79_get_ref_rate();
pll = __raw_readl(pll_base + AR724X_PLL_REG_CPU_CONFIG);
@@ -143,7 +136,6 @@ static void __init ar724x_clocks_init(void __iomem *pll_base)
static void __init ar933x_clocks_init(void __iomem *pll_base)
{
- unsigned long ref_rate;
u32 clock_ctrl;
u32 ref_div;
u32 ninit_mul;
@@ -152,15 +144,8 @@ static void __init ar933x_clocks_init(void __iomem *pll_base)
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)
- ref_rate = (40 * 1000 * 1000);
- else
- ref_rate = (25 * 1000 * 1000);
-
- ath79_setup_ref_clk(ref_rate);
+ ath79_get_ref_rate();
clock_ctrl = __raw_readl(pll_base + AR933X_PLL_CLOCK_CTRL_REG);
if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
@@ -237,18 +222,11 @@ static void __init ar934x_clocks_init(void __iomem *pll_base)
unsigned long ahb_rate;
u32 pll, out_div, ref_div, nint, nfrac, frac, clk_ctrl, postdiv;
u32 cpu_pll, ddr_pll;
- u32 bootstrap;
void __iomem *dpll_base;
dpll_base = ioremap(AR934X_SRIF_BASE, AR934X_SRIF_SIZE);
- bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
- if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40)
- ref_rate = 40 * 1000 * 1000;
- else
- ref_rate = 25 * 1000 * 1000;
-
- ref_rate = ath79_setup_ref_clk(ref_rate);
+ ref_rate = ath79_get_ref_rate();
pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL2_REG);
if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
@@ -355,15 +333,8 @@ static void __init qca953x_clocks_init(void __iomem *pll_base)
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);
+ ref_rate = ath79_get_ref_rate();
pll = __raw_readl(pll_base + QCA953X_PLL_CPU_CONFIG_REG);
out_div = (pll >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
@@ -438,15 +409,8 @@ static void __init qca955x_clocks_init(void __iomem *pll_base)
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)
- ref_rate = 40 * 1000 * 1000;
- else
- ref_rate = 25 * 1000 * 1000;
-
- ref_rate = ath79_setup_ref_clk(ref_rate);
+ ref_rate = ath79_get_ref_rate();
pll = __raw_readl(pll_base + QCA955X_PLL_CPU_CONFIG_REG);
out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
@@ -521,15 +485,8 @@ static void __init qca956x_clocks_init(void __iomem *pll_base)
unsigned long ahb_rate;
u32 pll, out_div, ref_div, nint, hfrac, lfrac, clk_ctrl, postdiv;
u32 cpu_pll, ddr_pll;
- u32 bootstrap;
-
- bootstrap = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
- if (bootstrap & QCA956X_BOOTSTRAP_REF_CLK_40)
- ref_rate = 40 * 1000 * 1000;
- else
- ref_rate = 25 * 1000 * 1000;
- ref_rate = ath79_setup_ref_clk(ref_rate);
+ ref_rate = ath79_get_ref_rate();
pll = __raw_readl(pll_base + QCA956X_PLL_CPU_CONFIG_REG);
out_div = (pll >> QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
@@ -610,7 +567,13 @@ static void __init ath79_clocks_init_dt(struct device_node *np)
struct clk *ref_clk;
void __iomem *pll_base;
+ /*
+ * The board's crystal. Without a rate in the device tree, the arch
+ * code registers it from the bootstrap pins.
+ */
ref_clk = of_clk_get(np, 0);
+ if (IS_ERR(ref_clk))
+ ref_clk = clk_get_sys(NULL, "ref");
if (!IS_ERR(ref_clk))
clks[ATH79_CLK_REF] = ref_clk;
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
index d9e1cc77ad04..dff0fbe07b04 100644
--- a/arch/mips/ath79/setup.c
+++ b/arch/mips/ath79/setup.c
@@ -15,6 +15,9 @@
#include <linux/memblock.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
#include <linux/of_clk.h>
#include <linux/of_fdt.h>
#include <linux/irqchip.h>
@@ -235,6 +238,89 @@ void __init plat_mem_setup(void)
pm_power_off = ath79_halt;
}
+static const struct of_device_id ath79_pll_ids[] __initconst = {
+ { .compatible = "qca,ar7100-pll" },
+ { .compatible = "qca,ar7240-pll" },
+ { .compatible = "qca,ar9130-pll" },
+ { .compatible = "qca,ar9330-pll" },
+ { .compatible = "qca,ar9340-pll" },
+ { .compatible = "qca,qca9530-pll" },
+ { .compatible = "qca,qca9550-pll" },
+ { .compatible = "qca,qca9560-pll" },
+ { /* sentinel */ }
+};
+
+/* the crystal that the bootstrap pins select */
+static unsigned long __init ath79_bootstrap_ref_rate(bool *strapped)
+{
+ unsigned int reg;
+ u32 bit;
+
+ *strapped = true;
+ if (soc_is_ar933x()) {
+ reg = AR933X_RESET_REG_BOOTSTRAP;
+ bit = AR933X_BOOTSTRAP_REF_CLK_40;
+ } else if (soc_is_ar934x()) {
+ reg = AR934X_RESET_REG_BOOTSTRAP;
+ bit = AR934X_BOOTSTRAP_REF_CLK_40;
+ } else if (soc_is_qca953x()) {
+ reg = QCA953X_RESET_REG_BOOTSTRAP;
+ bit = QCA953X_BOOTSTRAP_REF_CLK_40;
+ } else if (soc_is_qca955x()) {
+ reg = QCA955X_RESET_REG_BOOTSTRAP;
+ bit = QCA955X_BOOTSTRAP_REF_CLK_40;
+ } else if (soc_is_qca956x() || soc_is_tp9343()) {
+ reg = QCA956X_RESET_REG_BOOTSTRAP;
+ bit = QCA956X_BOOTSTRAP_REF_CLK_40;
+ } else {
+ /* no bootstrap pin for the crystal on AR71xx, AR724x, AR913x */
+ *strapped = false;
+ return 40000000;
+ }
+
+ return (ath79_reset_rr(reg) & bit) ? 40000000 : 25000000;
+}
+
+/*
+ * The clock code takes the reference clock from the device tree. Many
+ * AR933x boards leave its rate out and rely on the bootstrap pins, so
+ * register it from those for them. Otherwise warn if the device tree
+ * disagrees with the pins, as a wrong rate leaves every derived clock off,
+ * the UART baud rate included.
+ */
+static void __init ath79_setup_ref_clk(void)
+{
+ struct device_node *np, *ref_np;
+ unsigned long rate, strap_rate;
+ struct clk *clk;
+ bool strapped;
+ u32 dt_rate;
+
+ strap_rate = ath79_bootstrap_ref_rate(&strapped);
+
+ np = of_find_matching_node(NULL, ath79_pll_ids);
+ ref_np = np ? of_parse_phandle(np, "clocks", 0) : NULL;
+ of_node_put(np);
+
+ if (ref_np && !of_property_read_u32(ref_np, "clock-frequency", &dt_rate)) {
+ of_node_put(ref_np);
+ rate = dt_rate;
+ if (strapped && rate != strap_rate)
+ pr_warn("ath79: reference clock is %lu Hz in the device tree, but the bootstrap pins select %lu Hz\n",
+ rate, strap_rate);
+ return;
+ }
+ of_node_put(ref_np);
+
+ clk = clk_register_fixed_rate(NULL, "ref", NULL, 0, strap_rate);
+ if (IS_ERR(clk)) {
+ pr_err("ath79: failed to register the reference clock\n");
+ return;
+ }
+
+ clk_register_clkdev(clk, "ref", NULL);
+}
+
void __init plat_time_init(void)
{
struct device_node *np;
@@ -254,6 +340,7 @@ void __init plat_time_init(void)
ath79_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, misc);
}
+ ath79_setup_ref_clk();
of_clk_init(NULL);
np = of_get_cpu_node(0, NULL);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v2 5/6] clk: add a driver for the Atheros/Qualcomm ath79 PLL controller
2026-11-10 1:36 [PATCH v2 0/6] clk: add a driver for the ath79 PLL controller Rosen Penev
` (3 preceding siblings ...)
2026-11-10 1:36 ` [PATCH v2 4/6] dt-bindings: clock: ath79: add the PCIe PLL clock Rosen Penev
@ 2026-11-10 1:36 ` Rosen Penev
2026-11-10 1:36 ` [PATCH v2 6/6] MIPS: ath79: remove the old clock code Rosen Penev
5 siblings, 0 replies; 7+ messages in thread
From: Rosen Penev @ 2026-11-10 1:36 UTC (permalink / raw)
To: Thomas Bogendoerfer, Stephen Boyd, Brian Masney, Jerome Brunet,
Alban Bedel, Antony Pavlov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, linux-mips, linux-clk, devicetree
The ath79 clocks are set up by arch/mips/ath79/clock.c, a CLK_OF_DECLARE
driver that registers every clock before the driver core is up. Add a
replacement in drivers/clk.
Only the reference and CPU clocks are registered early, with
CLK_OF_DECLARE_DRIVER(), as the MIPS timer needs the CPU rate from
plat_time_init(). The other clocks come from a platform driver for the
same node, like the MT7621 clocks do. The early provider returns
-EPROBE_DEFER for them until the platform driver fills them in.
The bootloader sets up the PLLs, and the CPU, DDR and AHB clocks are
read back from the registers as fixed rates, as before. Compared to the
arch code:
- Each SoC is described by match data: a function that reads the rates,
and for AR934x and later the bits of CPU_DDR_CLOCK_CONTROL that select
a PLL for each clock. The bypass bits and post dividers of that
register are the same on every SoC, so one function handles them.
AR934x, QCA953x and QCA955x share the fractional PLL calculation, done
with 64-bit intermediates.
- The AR724x and AR933x clocks were fixed factors of a parent named
"ref". They are fixed rates now, like the others, all with the
reference clock's clk_hw as the parent.
- Invalid register contents, a reference clock that is missing and
registration failures are reported instead of causing a panic or a
division by zero.
- The AR934x SRIF block, which holds the CPU and DDR DPLLs, is still
mapped from its fixed address. It lies inside the register space of
the wireless MAC, which ath9k claims, so it can't be a reg entry of
the PLL node. The driver only reads it and doesn't claim it.
- The clocks are no longer registered with clkdev. No driver looks them
up by name.
- AR934x gets its UART1 clock: 100 MHz when UART1_CLK_SEL is set in
SWITCH_CLOCK_CONTROL, the reference clock otherwise and on the other
SoCs. This is based on an OpenWrt patch by Daniel Golle.
- The PCIe PLL is a clock, so that a PCIe host driver can use the clk
API instead of poking the PLL block through the arch code. Prepare
powers the PLL up and takes it out of bypass, waiting for UPDATING to
clear after each step. Every write to the register freezes the high
speed clocks for about 60 us (AR7242 datasheet, 4.4.4), so a PLL the
bootloader already started is left alone. AR724x holds the PLL in
reset instead of powering it down, and the register is at 0x10 on
AR724x, AR934x and QCA953x, 0x0c on QCA955x and 0x14 on QCA956x. The
clock is CLK_IGNORE_UNUSED, so a PLL that no driver claims stays as
the bootloader left it.
The rates match the arch code for every SoC, checked in userspace
against it with random register values. They differ only where the
arch code overflowed 32 bits with register values that no real
setup uses.
COMMON_CLK_ATH79 defaults to ATH79, and arch/mips/ath79/clock.c is no
longer built when it is enabled.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
MAINTAINERS | 8 +
arch/mips/ath79/Makefile | 5 +-
drivers/clk/Kconfig | 12 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-ath79.c | 778 +++++++++++++++++++++++++++++++++++++++
5 files changed, 803 insertions(+), 1 deletion(-)
create mode 100644 drivers/clk/clk-ath79.c
diff --git a/MAINTAINERS b/MAINTAINERS
index c57be10c8729..98f42425b37d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4341,6 +4341,14 @@ S: Supported
F: Documentation/devicetree/bindings/rtc/andestech,atcrtc100.yaml
F: drivers/rtc/rtc-atcrtc100.c
+ATHEROS 71XX/9XXX CLOCK DRIVER
+M: Alban Bedel <albeu@free.fr>
+M: Antony Pavlov <antonynpavlov@gmail.com>
+S: Maintained
+F: Documentation/devicetree/bindings/clock/qca,ath79-pll.yaml
+F: drivers/clk/clk-ath79.c
+F: include/dt-bindings/clock/ath79-clk.h
+
ATHEROS 71XX/9XXX GPIO DRIVER
M: Alban Bedel <albeu@free.fr>
S: Maintained
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
index 0fb3aaf42149..b78ffdc9b389 100644
--- a/arch/mips/ath79/Makefile
+++ b/arch/mips/ath79/Makefile
@@ -6,6 +6,9 @@
# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
#
-obj-y := prom.o setup.o common.o clock.o
+obj-y := prom.o setup.o common.o
+
+# replaced by the clk-ath79 driver
+obj-$(if $(CONFIG_COMMON_CLK_ATH79),,y) += clock.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 37a8e35d4178..bd5f77cddfe0 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -66,6 +66,18 @@ config COMMON_CLK_APPLE_NCO
found on Apple SoCs such as t8103 (M1). The blocks are typically
generators of audio clocks.
+config COMMON_CLK_ATH79
+ bool "Clock driver for Atheros/Qualcomm ath79 SoCs" if COMPILE_TEST
+ depends on ATH79 || COMPILE_TEST
+ depends on OF
+ default ATH79
+ help
+ Support for the PLL controller of the Atheros/Qualcomm ath79
+ family of MIPS SoCs: AR71xx, AR724x, AR913x, AR933x, AR934x,
+ QCA953x, QCA955x and QCA956x. It provides the CPU, DDR, AHB,
+ MDIO, UART1 and PCIe clocks, derived from the board's reference
+ clock.
+
config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77620/77686/77802 MFD"
depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 52d138d4ffc8..589d2ef9dc89 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -58,6 +58,7 @@ endif
# please keep this section sorted lexicographically by file path name
obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
+obj-$(CONFIG_COMMON_CLK_ATH79) += clk-ath79.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_COMMON_CLK_BD718XX) += clk-bd718x7.o
diff --git a/drivers/clk/clk-ath79.c b/drivers/clk/clk-ath79.c
new file mode 100644
index 000000000000..3ddbd020afb1
--- /dev/null
+++ b/drivers/clk/clk-ath79.c
@@ -0,0 +1,778 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Atheros/Qualcomm ath79 PLL controller
+ *
+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
+ *
+ * The bootloader sets up the CPU, DDR and AHB clocks, and they are read
+ * back here as fixed rates. The CPU clock is registered early, as the
+ * MIPS timer needs it from plat_time_init(). The other clocks are
+ * registered by the platform driver.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/math64.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/ath79-clk.h>
+
+#define AR71XX_PLL_CPU_CONFIG_REG 0x00
+#define AR71XX_PLL_FB GENMASK(7, 3)
+#define AR71XX_CPU_DIV GENMASK(17, 16)
+#define AR71XX_DDR_DIV GENMASK(19, 18)
+#define AR71XX_AHB_DIV GENMASK(22, 20)
+
+#define AR724X_PLL_CPU_CONFIG_REG 0x00
+#define AR724X_PLL_FB GENMASK(9, 0)
+#define AR724X_PLL_REF_DIV GENMASK(13, 10)
+#define AR724X_AHB_DIV GENMASK(19, 19)
+#define AR724X_DDR_DIV GENMASK(23, 22)
+#define AR724X_PLL_PCIE_CONFIG_REG 0x10
+#define AR724X_PLL_PCIE_CONFIG_PLL_BYPASS BIT(16)
+#define AR724X_PLL_PCIE_CONFIG_UPDATING BIT(17)
+#define AR724X_PLL_PCIE_CONFIG_PLL_RESET BIT(25)
+
+#define AR933X_PLL_CPU_CONFIG_REG 0x00
+#define AR933X_PLL_CLOCK_CTRL_REG 0x08
+#define AR933X_PLL_CPU_CONFIG_NINT GENMASK(15, 10)
+#define AR933X_PLL_CPU_CONFIG_REFDIV GENMASK(20, 16)
+#define AR933X_PLL_CPU_CONFIG_OUTDIV GENMASK(25, 23)
+#define AR933X_PLL_CLOCK_CTRL_BYPASS BIT(2)
+#define AR933X_PLL_CLOCK_CTRL_CPU_DIV GENMASK(6, 5)
+#define AR933X_PLL_CLOCK_CTRL_DDR_DIV GENMASK(11, 10)
+#define AR933X_PLL_CLOCK_CTRL_AHB_DIV GENMASK(17, 15)
+
+/* AR934x, QCA953x and QCA955x */
+#define AR934X_PLL_CPU_CONFIG_REG 0x00
+#define AR934X_PLL_DDR_CONFIG_REG 0x04
+#define AR934X_PLL_CLK_CTRL_REG 0x08
+#define AR934X_PLL_PCIE_CONFIG_REG 0x10
+#define AR934X_PLL_SWITCH_CLOCK_CONTROL_REG 0x24
+#define AR934X_PLL_CPU_CONFIG_NFRAC GENMASK(5, 0)
+#define AR934X_PLL_CPU_CONFIG_NINT GENMASK(11, 6)
+#define AR934X_PLL_CPU_CONFIG_REFDIV GENMASK(16, 12)
+#define AR934X_PLL_CPU_CONFIG_OUTDIV GENMASK(20, 19)
+#define QCA953X_PLL_CPU_CONFIG_OUTDIV GENMASK(21, 19)
+#define AR934X_PLL_DDR_CONFIG_NFRAC GENMASK(9, 0)
+#define AR934X_PLL_DDR_CONFIG_NINT GENMASK(15, 10)
+#define AR934X_PLL_DDR_CONFIG_REFDIV GENMASK(20, 16)
+#define AR934X_PLL_DDR_CONFIG_OUTDIV GENMASK(25, 23)
+#define AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL BIT(6)
+#define AR934X_PLL_SWITCH_CLOCK_CONTROL_UART1_CLK_SEL BIT(7)
+#define AR934X_PLL_PCIE_CONFIG_PLL_BYPASS BIT(16)
+#define AR934X_PLL_PCIE_CONFIG_PLL_PWD BIT(30)
+#define AR934X_PLL_PCIE_CONFIG_UPDATING BIT(31)
+
+#define QCA955X_PLL_PCIE_CONFIG_REG 0x0c
+
+#define QCA956X_PLL_CPU_CONFIG_REG 0x00
+#define QCA956X_PLL_CPU_CONFIG1_REG 0x04
+#define QCA956X_PLL_DDR_CONFIG_REG 0x08
+#define QCA956X_PLL_DDR_CONFIG1_REG 0x0c
+#define QCA956X_PLL_CLK_CTRL_REG 0x10
+#define QCA956X_PLL_PCIE_CONFIG_REG 0x14
+#define QCA956X_PLL_CPU_CONFIG_REFDIV GENMASK(16, 12)
+#define QCA956X_PLL_CPU_CONFIG_OUTDIV GENMASK(21, 19)
+#define QCA956X_PLL_DDR_CONFIG_REFDIV GENMASK(20, 16)
+#define QCA956X_PLL_DDR_CONFIG_OUTDIV GENMASK(25, 23)
+#define QCA956X_PLL_CONFIG1_NFRAC_L GENMASK(4, 0)
+#define QCA956X_PLL_CONFIG1_NFRAC_H GENMASK(17, 5)
+#define QCA956X_PLL_CONFIG1_NINT GENMASK(26, 18)
+
+/*
+ * CPU_DDR_CLOCK_CONTROL on AR934x and later: a bypass bit and a post
+ * divider for each of the CPU, DDR and AHB clocks, at the same place on
+ * every SoC. Which PLL a clock takes and the bit selecting it differ.
+ */
+#define ATH79_CLK_CTRL_BYPASS(i) BIT(2 + (i))
+#define ATH79_CLK_CTRL_POST_DIV_SHIFT(i) (5 + 5 * (i))
+#define ATH79_CLK_CTRL_POST_DIV_MASK 0x1f
+
+/*
+ * The SRIF block holds the AR934x DPLLs. It sits inside the register
+ * space of the wireless MAC, which claims it, so it is mapped from its
+ * fixed address and only read.
+ */
+#define AR934X_SRIF_BASE 0x18116000
+#define AR934X_SRIF_SIZE 0x1000
+#define AR934X_SRIF_CPU_DPLL1_REG 0x1c0
+#define AR934X_SRIF_CPU_DPLL2_REG 0x1c4
+#define AR934X_SRIF_DDR_DPLL1_REG 0x240
+#define AR934X_SRIF_DDR_DPLL2_REG 0x244
+#define AR934X_SRIF_DPLL1_REFDIV GENMASK(31, 27)
+#define AR934X_SRIF_DPLL1_NINT GENMASK(26, 18)
+#define AR934X_SRIF_DPLL1_NFRAC GENMASK(17, 0)
+#define AR934X_SRIF_DPLL2_LOCAL_PLL BIT(30)
+#define AR934X_SRIF_DPLL2_OUTDIV GENMASK(15, 13)
+
+#define ATH79_SWITCH_CLK_RATE 100000000
+
+enum { ATH79_OUT_CPU, ATH79_OUT_DDR, ATH79_OUT_AHB, ATH79_OUT_NUM };
+
+struct ath79_clk_regs {
+ void __iomem *pll;
+ void __iomem *srif; /* AR934x only */
+};
+
+struct ath79_clk_ctrl_sel {
+ u32 bit;
+ bool set_is_cpu_pll; /* the bit selects the CPU PLL, not the DDR PLL */
+};
+
+struct ath79_pcie_pll_desc {
+ unsigned int reg;
+ u32 pwd; /* powers the PLL down or holds it in reset */
+ u32 bypass;
+ u32 updating; /* set while a new setting is being applied */
+};
+
+struct ath79_clk_soc_data {
+ int (*get_rates)(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs, unsigned long ref,
+ unsigned long *rates);
+ /* AR934x, QCA953x and QCA955x */
+ u32 cpu_outdiv;
+ /* AR934x and later */
+ struct ath79_clk_ctrl_sel sel[ATH79_OUT_NUM];
+ const struct ath79_pcie_pll_desc *pcie;
+ bool has_srif;
+ bool has_switch_clk; /* AR934x MDIO and UART1 clock selection */
+};
+
+struct ath79_pcie_pll {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 pwd;
+ u32 bypass;
+ u32 updating;
+};
+
+#define to_ath79_pcie_pll(_hw) container_of(_hw, struct ath79_pcie_pll, hw)
+
+/*
+ * The provider registered early. It holds the reference and CPU clocks,
+ * and the platform driver fills in the others.
+ */
+static struct clk_hw_onecell_data *ath79_clk_data;
+
+/* ref * mult / div, or 0 for an unset divider */
+static unsigned long ath79_ref_mul_div(unsigned long ref, u32 mult, u32 div)
+{
+ return div ? div_u64((u64)ref * mult, div) : 0;
+}
+
+/* a fractional PLL: ref / ref_div * (nint + nfrac / frac) / 2^out_div */
+static unsigned long ath79_pll_rate(unsigned long ref, u32 ref_div, u32 nint,
+ u32 nfrac, u32 frac, u32 out_div)
+{
+ u64 rate;
+
+ if (!ref_div)
+ return 0;
+
+ rate = div_u64((u64)ref * nint, ref_div);
+ rate += div_u64((u64)ref * nfrac, ref_div * frac);
+
+ return rate >> out_div;
+}
+
+static int ar71xx_get_rates(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs,
+ unsigned long ref, unsigned long *rates)
+{
+ unsigned long freq;
+ u32 pll;
+
+ pll = readl(regs->pll + AR71XX_PLL_CPU_CONFIG_REG);
+
+ freq = ref * (FIELD_GET(AR71XX_PLL_FB, pll) + 1);
+ rates[ATH79_OUT_CPU] = freq / (FIELD_GET(AR71XX_CPU_DIV, pll) + 1);
+ rates[ATH79_OUT_DDR] = freq / (FIELD_GET(AR71XX_DDR_DIV, pll) + 1);
+ rates[ATH79_OUT_AHB] = rates[ATH79_OUT_CPU] /
+ ((FIELD_GET(AR71XX_AHB_DIV, pll) + 1) * 2);
+
+ return 0;
+}
+
+static int ar724x_get_rates(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs,
+ unsigned long ref, unsigned long *rates)
+{
+ u32 pll, mult, div, ddr_div, ahb_div;
+
+ pll = readl(regs->pll + AR724X_PLL_CPU_CONFIG_REG);
+
+ mult = FIELD_GET(AR724X_PLL_FB, pll);
+ div = FIELD_GET(AR724X_PLL_REF_DIV, pll) * 2;
+ ddr_div = FIELD_GET(AR724X_DDR_DIV, pll) + 1;
+ ahb_div = (FIELD_GET(AR724X_AHB_DIV, pll) + 1) * 2;
+
+ rates[ATH79_OUT_CPU] = ath79_ref_mul_div(ref, mult, div);
+ rates[ATH79_OUT_DDR] = ath79_ref_mul_div(ref, mult, div * ddr_div);
+ rates[ATH79_OUT_AHB] = ath79_ref_mul_div(ref, mult, div * ahb_div);
+
+ return 0;
+}
+
+static int ar933x_get_rates(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs,
+ unsigned long ref, unsigned long *rates)
+{
+ u32 ctrl, pll, nint, div, out_div, cpu_div, ddr_div, ahb_div;
+
+ ctrl = readl(regs->pll + AR933X_PLL_CLOCK_CTRL_REG);
+ if (ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
+ rates[ATH79_OUT_CPU] = ref;
+ rates[ATH79_OUT_DDR] = ref;
+ rates[ATH79_OUT_AHB] = ref;
+ return 0;
+ }
+
+ pll = readl(regs->pll + AR933X_PLL_CPU_CONFIG_REG);
+
+ nint = FIELD_GET(AR933X_PLL_CPU_CONFIG_NINT, pll);
+ out_div = FIELD_GET(AR933X_PLL_CPU_CONFIG_OUTDIV, pll);
+ div = FIELD_GET(AR933X_PLL_CPU_CONFIG_REFDIV, pll) << max(out_div, 1U);
+ cpu_div = FIELD_GET(AR933X_PLL_CLOCK_CTRL_CPU_DIV, ctrl) + 1;
+ ddr_div = FIELD_GET(AR933X_PLL_CLOCK_CTRL_DDR_DIV, ctrl) + 1;
+ ahb_div = FIELD_GET(AR933X_PLL_CLOCK_CTRL_AHB_DIV, ctrl) + 1;
+
+ rates[ATH79_OUT_CPU] = ath79_ref_mul_div(ref, nint, div * cpu_div);
+ rates[ATH79_OUT_DDR] = ath79_ref_mul_div(ref, nint, div * ddr_div);
+ rates[ATH79_OUT_AHB] = ath79_ref_mul_div(ref, nint, div * ahb_div);
+
+ return 0;
+}
+
+/* the CPU, DDR and AHB clocks from CPU_DDR_CLOCK_CONTROL */
+static void ath79_clk_ctrl_rates(const struct ath79_clk_soc_data *soc,
+ u32 ctrl, unsigned long ref,
+ unsigned long cpu_pll, unsigned long ddr_pll,
+ unsigned long *rates)
+{
+ const struct ath79_clk_ctrl_sel *sel;
+ unsigned long pll;
+ u32 post_div;
+ int i;
+
+ for (i = 0; i < ATH79_OUT_NUM; i++) {
+ if (ctrl & ATH79_CLK_CTRL_BYPASS(i)) {
+ rates[i] = ref;
+ continue;
+ }
+
+ sel = &soc->sel[i];
+ pll = !!(ctrl & sel->bit) == sel->set_is_cpu_pll ? cpu_pll
+ : ddr_pll;
+ post_div = (ctrl >> ATH79_CLK_CTRL_POST_DIV_SHIFT(i)) &
+ ATH79_CLK_CTRL_POST_DIV_MASK;
+ rates[i] = pll / (post_div + 1);
+ }
+}
+
+/* the AR934x DPLLs in the SRIF block, when they drive the CPU or DDR clock */
+static bool ar934x_srif_pll_rate(const struct ath79_clk_regs *regs,
+ unsigned int dpll1, unsigned int dpll2,
+ unsigned long ref, unsigned long *rate)
+{
+ u32 pll, out_div;
+
+ if (!regs->srif)
+ return false;
+
+ pll = readl(regs->srif + dpll2);
+ if (!(pll & AR934X_SRIF_DPLL2_LOCAL_PLL))
+ return false;
+
+ out_div = FIELD_GET(AR934X_SRIF_DPLL2_OUTDIV, pll);
+ pll = readl(regs->srif + dpll1);
+ *rate = ath79_pll_rate(ref, FIELD_GET(AR934X_SRIF_DPLL1_REFDIV, pll),
+ FIELD_GET(AR934X_SRIF_DPLL1_NINT, pll),
+ FIELD_GET(AR934X_SRIF_DPLL1_NFRAC, pll),
+ 1 << 18, out_div);
+ return true;
+}
+
+/* AR934x, QCA953x and QCA955x */
+static int ar934x_get_rates(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs,
+ unsigned long ref, unsigned long *rates)
+{
+ unsigned long cpu_pll, ddr_pll;
+ u32 pll, ref_div, nint, nfrac, out_div;
+
+ if (!ar934x_srif_pll_rate(regs, AR934X_SRIF_CPU_DPLL1_REG,
+ AR934X_SRIF_CPU_DPLL2_REG, ref, &cpu_pll)) {
+ pll = readl(regs->pll + AR934X_PLL_CPU_CONFIG_REG);
+ ref_div = FIELD_GET(AR934X_PLL_CPU_CONFIG_REFDIV, pll);
+ nint = FIELD_GET(AR934X_PLL_CPU_CONFIG_NINT, pll);
+ nfrac = FIELD_GET(AR934X_PLL_CPU_CONFIG_NFRAC, pll);
+ out_div = (pll & soc->cpu_outdiv) >> __ffs(soc->cpu_outdiv);
+ cpu_pll = ath79_pll_rate(ref, ref_div, nint, nfrac, 1 << 6,
+ out_div);
+ }
+
+ if (!ar934x_srif_pll_rate(regs, AR934X_SRIF_DDR_DPLL1_REG,
+ AR934X_SRIF_DDR_DPLL2_REG, ref, &ddr_pll)) {
+ pll = readl(regs->pll + AR934X_PLL_DDR_CONFIG_REG);
+ ref_div = FIELD_GET(AR934X_PLL_DDR_CONFIG_REFDIV, pll);
+ nint = FIELD_GET(AR934X_PLL_DDR_CONFIG_NINT, pll);
+ nfrac = FIELD_GET(AR934X_PLL_DDR_CONFIG_NFRAC, pll);
+ out_div = FIELD_GET(AR934X_PLL_DDR_CONFIG_OUTDIV, pll);
+ ddr_pll = ath79_pll_rate(ref, ref_div, nint, nfrac, 1 << 10,
+ out_div);
+ }
+
+ ath79_clk_ctrl_rates(soc, readl(regs->pll + AR934X_PLL_CLK_CTRL_REG),
+ ref, cpu_pll, ddr_pll, rates);
+ return 0;
+}
+
+static unsigned long qca956x_pll_rate(unsigned long ref, u32 config,
+ u32 config1, u32 refdiv_mask,
+ u32 outdiv_mask)
+{
+ u32 ref_div, out_div, nint, hfrac, lfrac;
+ u64 rate;
+
+ ref_div = (config & refdiv_mask) >> __ffs(refdiv_mask);
+ out_div = (config & outdiv_mask) >> __ffs(outdiv_mask);
+ nint = FIELD_GET(QCA956X_PLL_CONFIG1_NINT, config1);
+ hfrac = FIELD_GET(QCA956X_PLL_CONFIG1_NFRAC_H, config1);
+ lfrac = FIELD_GET(QCA956X_PLL_CONFIG1_NFRAC_L, config1);
+
+ if (!ref_div)
+ return 0;
+
+ rate = div_u64((u64)ref * nint, ref_div);
+ rate += div_u64((u64)ref * lfrac, (ref_div * 25) << 13);
+ rate += div_u64((u64)ref * (hfrac >> 13), ref_div);
+
+ return rate >> out_div;
+}
+
+static int qca956x_get_rates(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs,
+ unsigned long ref, unsigned long *rates)
+{
+ unsigned long cpu_pll, ddr_pll;
+
+ cpu_pll = qca956x_pll_rate(ref,
+ readl(regs->pll + QCA956X_PLL_CPU_CONFIG_REG),
+ readl(regs->pll + QCA956X_PLL_CPU_CONFIG1_REG),
+ QCA956X_PLL_CPU_CONFIG_REFDIV,
+ QCA956X_PLL_CPU_CONFIG_OUTDIV);
+ ddr_pll = qca956x_pll_rate(ref,
+ readl(regs->pll + QCA956X_PLL_DDR_CONFIG_REG),
+ readl(regs->pll + QCA956X_PLL_DDR_CONFIG1_REG),
+ QCA956X_PLL_DDR_CONFIG_REFDIV,
+ QCA956X_PLL_DDR_CONFIG_OUTDIV);
+
+ ath79_clk_ctrl_rates(soc, readl(regs->pll + QCA956X_PLL_CLK_CTRL_REG),
+ ref, cpu_pll, ddr_pll, rates);
+ return 0;
+}
+
+static int ath79_get_rates(const struct ath79_clk_soc_data *soc,
+ const struct ath79_clk_regs *regs, unsigned long ref,
+ unsigned long *rates)
+{
+ int ret, i;
+
+ ret = soc->get_rates(soc, regs, ref, rates);
+ if (ret)
+ return ret;
+
+ /* a zero divider in the registers */
+ for (i = 0; i < ATH79_OUT_NUM; i++)
+ if (!rates[i])
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ath79_pcie_pll_wait(struct ath79_pcie_pll *pll)
+{
+ u32 t;
+
+ return readl_poll_timeout(pll->reg, t, !(t & pll->updating), 10, 1000);
+}
+
+static int ath79_pcie_pll_is_prepared(struct clk_hw *hw)
+{
+ struct ath79_pcie_pll *pll = to_ath79_pcie_pll(hw);
+
+ return !(readl(pll->reg) & (pll->pwd | pll->bypass));
+}
+
+static int ath79_pcie_pll_prepare(struct clk_hw *hw)
+{
+ struct ath79_pcie_pll *pll = to_ath79_pcie_pll(hw);
+ u32 t;
+ int ret;
+
+ /*
+ * Every write freezes the high speed clocks for about 60 us, so
+ * leave a PLL that the bootloader already started alone.
+ */
+ if (ath79_pcie_pll_is_prepared(hw))
+ return 0;
+
+ t = readl(pll->reg) & ~pll->pwd;
+ writel(t, pll->reg);
+ ret = ath79_pcie_pll_wait(pll);
+ if (ret)
+ return ret;
+
+ writel(t & ~pll->bypass, pll->reg);
+ return ath79_pcie_pll_wait(pll);
+}
+
+static void ath79_pcie_pll_unprepare(struct clk_hw *hw)
+{
+ struct ath79_pcie_pll *pll = to_ath79_pcie_pll(hw);
+ u32 t;
+
+ t = readl(pll->reg) | pll->bypass;
+ writel(t, pll->reg);
+ writel(t | pll->pwd, pll->reg);
+}
+
+static const struct clk_ops ath79_pcie_pll_ops = {
+ .prepare = ath79_pcie_pll_prepare,
+ .unprepare = ath79_pcie_pll_unprepare,
+ .is_prepared = ath79_pcie_pll_is_prepared,
+};
+
+static struct clk_hw *ath79_pcie_pll_register(struct device *dev,
+ void __iomem *base,
+ const struct ath79_pcie_pll_desc *desc)
+{
+ struct clk_init_data init = {
+ .name = "pcie",
+ .ops = &ath79_pcie_pll_ops,
+ /* keep a PLL that no driver claims as the bootloader left it */
+ .flags = CLK_IGNORE_UNUSED,
+ };
+ struct ath79_pcie_pll *pll;
+ int ret;
+
+ pll = devm_kzalloc_obj(dev, *pll);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->reg = base + desc->reg;
+ pll->pwd = desc->pwd;
+ pll->bypass = desc->bypass;
+ pll->updating = desc->updating;
+ pll->hw.init = &init;
+
+ ret = devm_clk_hw_register(dev, &pll->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &pll->hw;
+}
+
+/* AR724x holds the PLL in reset instead of powering it down */
+static const struct ath79_pcie_pll_desc ar724x_pcie_pll = {
+ .reg = AR724X_PLL_PCIE_CONFIG_REG,
+ .pwd = AR724X_PLL_PCIE_CONFIG_PLL_RESET,
+ .bypass = AR724X_PLL_PCIE_CONFIG_PLL_BYPASS,
+ .updating = AR724X_PLL_PCIE_CONFIG_UPDATING,
+};
+
+#define AR934X_PCIE_PLL(_reg) \
+ { \
+ .reg = (_reg), \
+ .pwd = AR934X_PLL_PCIE_CONFIG_PLL_PWD, \
+ .bypass = AR934X_PLL_PCIE_CONFIG_PLL_BYPASS, \
+ .updating = AR934X_PLL_PCIE_CONFIG_UPDATING, \
+ }
+
+static const struct ath79_pcie_pll_desc ar934x_pcie_pll =
+ AR934X_PCIE_PLL(AR934X_PLL_PCIE_CONFIG_REG);
+static const struct ath79_pcie_pll_desc qca955x_pcie_pll =
+ AR934X_PCIE_PLL(QCA955X_PLL_PCIE_CONFIG_REG);
+static const struct ath79_pcie_pll_desc qca956x_pcie_pll =
+ AR934X_PCIE_PLL(QCA956X_PLL_PCIE_CONFIG_REG);
+
+static const struct ath79_clk_soc_data ar7100_clk_data = {
+ .get_rates = ar71xx_get_rates,
+};
+
+static const struct ath79_clk_soc_data ar7240_clk_data = {
+ .get_rates = ar724x_get_rates,
+ .pcie = &ar724x_pcie_pll,
+};
+
+/* AR913x is an AR724x without PCIe */
+static const struct ath79_clk_soc_data ar9130_clk_data = {
+ .get_rates = ar724x_get_rates,
+};
+
+static const struct ath79_clk_soc_data ar9330_clk_data = {
+ .get_rates = ar933x_get_rates,
+};
+
+static const struct ath79_clk_soc_data ar9340_clk_data = {
+ .get_rates = ar934x_get_rates,
+ .cpu_outdiv = AR934X_PLL_CPU_CONFIG_OUTDIV,
+ .sel = {
+ [ATH79_OUT_CPU] = { BIT(20), true },
+ [ATH79_OUT_DDR] = { BIT(21), false },
+ [ATH79_OUT_AHB] = { BIT(24), false },
+ },
+ .pcie = &ar934x_pcie_pll,
+ .has_srif = true,
+ .has_switch_clk = true,
+};
+
+static const struct ath79_clk_soc_data qca9530_clk_data = {
+ .get_rates = ar934x_get_rates,
+ .cpu_outdiv = QCA953X_PLL_CPU_CONFIG_OUTDIV,
+ .sel = {
+ [ATH79_OUT_CPU] = { BIT(20), true },
+ [ATH79_OUT_DDR] = { BIT(21), false },
+ [ATH79_OUT_AHB] = { BIT(24), false },
+ },
+ .pcie = &ar934x_pcie_pll,
+};
+
+static const struct ath79_clk_soc_data qca9550_clk_data = {
+ .get_rates = ar934x_get_rates,
+ .cpu_outdiv = AR934X_PLL_CPU_CONFIG_OUTDIV,
+ .sel = {
+ [ATH79_OUT_CPU] = { BIT(20), false },
+ [ATH79_OUT_DDR] = { BIT(21), true },
+ [ATH79_OUT_AHB] = { BIT(24), false },
+ },
+ .pcie = &qca955x_pcie_pll,
+};
+
+static const struct ath79_clk_soc_data qca9560_clk_data = {
+ .get_rates = qca956x_get_rates,
+ .sel = {
+ [ATH79_OUT_CPU] = { BIT(21), false },
+ [ATH79_OUT_DDR] = { BIT(20), true },
+ [ATH79_OUT_AHB] = { BIT(24), false },
+ },
+ .pcie = &qca956x_pcie_pll,
+};
+
+static const struct of_device_id ath79_clk_of_match[] = {
+ { .compatible = "qca,ar7100-pll", .data = &ar7100_clk_data },
+ { .compatible = "qca,ar7240-pll", .data = &ar7240_clk_data },
+ { .compatible = "qca,ar9130-pll", .data = &ar9130_clk_data },
+ { .compatible = "qca,ar9330-pll", .data = &ar9330_clk_data },
+ { .compatible = "qca,ar9340-pll", .data = &ar9340_clk_data },
+ { .compatible = "qca,qca9530-pll", .data = &qca9530_clk_data },
+ { .compatible = "qca,qca9550-pll", .data = &qca9550_clk_data },
+ { .compatible = "qca,qca9560-pll", .data = &qca9560_clk_data },
+ { /* sentinel */ }
+};
+
+static void __init ath79_clk_early_init(struct device_node *np)
+{
+ const struct ath79_clk_soc_data *soc;
+ unsigned long rates[ATH79_OUT_NUM];
+ struct ath79_clk_regs regs = {};
+ struct clk_hw *ref, *cpu;
+ struct clk *ref_clk;
+ int ret, i;
+
+ soc = of_match_node(ath79_clk_of_match, np)->data;
+
+ /*
+ * The board's crystal. Old device trees leave its rate out, and the
+ * arch code then registers it from the bootstrap pins as "ref".
+ */
+ ref_clk = of_clk_get_by_name(np, "ref");
+ if (IS_ERR(ref_clk))
+ ref_clk = clk_get_sys(NULL, "ref");
+ if (IS_ERR(ref_clk)) {
+ pr_err("%pOF: no reference clock\n", np);
+ return;
+ }
+ ref = __clk_get_hw(ref_clk);
+
+ regs.pll = of_iomap(np, 0);
+ if (!regs.pll) {
+ pr_err("%pOF: can't map the PLL registers\n", np);
+ goto err_put_ref;
+ }
+
+ if (soc->has_srif) {
+ regs.srif = ioremap(AR934X_SRIF_BASE, AR934X_SRIF_SIZE);
+ if (!regs.srif) {
+ pr_err("%pOF: can't map the SRIF registers\n", np);
+ iounmap(regs.pll);
+ goto err_put_ref;
+ }
+ }
+
+ ret = ath79_get_rates(soc, ®s, clk_hw_get_rate(ref), rates);
+
+ if (regs.srif)
+ iounmap(regs.srif);
+ iounmap(regs.pll);
+
+ if (ret) {
+ pr_err("%pOF: invalid PLL setup\n", np);
+ goto err_put_ref;
+ }
+
+ ath79_clk_data = kzalloc_flex(*ath79_clk_data, hws, ATH79_CLK_END);
+ if (!ath79_clk_data)
+ goto err_put_ref;
+
+ ath79_clk_data->num = ATH79_CLK_END;
+ for (i = 0; i < ATH79_CLK_END; i++)
+ ath79_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+ cpu = clk_hw_register_fixed_rate_parent_hw(NULL, "cpu", ref, 0,
+ rates[ATH79_OUT_CPU]);
+ if (IS_ERR(cpu)) {
+ pr_err("%pOF: failed to register the CPU clock: %pe\n", np, cpu);
+ goto err_free_data;
+ }
+
+ ath79_clk_data->hws[ATH79_CLK_REF] = ref;
+ ath79_clk_data->hws[ATH79_CLK_CPU] = cpu;
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ath79_clk_data);
+ if (ret) {
+ pr_err("%pOF: failed to add the clock provider: %pe\n", np,
+ ERR_PTR(ret));
+ clk_hw_unregister_fixed_rate(cpu);
+ goto err_free_data;
+ }
+
+ return;
+
+err_free_data:
+ kfree(ath79_clk_data);
+ ath79_clk_data = NULL;
+err_put_ref:
+ clk_put(ref_clk);
+}
+
+CLK_OF_DECLARE_DRIVER(ar7100_clk, "qca,ar7100-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(ar7240_clk, "qca,ar7240-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(ar9130_clk, "qca,ar9130-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(ar9330_clk, "qca,ar9330-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(ar9340_clk, "qca,ar9340-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(qca9530_clk, "qca,qca9530-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(qca9550_clk, "qca,qca9550-pll", ath79_clk_early_init);
+CLK_OF_DECLARE_DRIVER(qca9560_clk, "qca,qca9560-pll", ath79_clk_early_init);
+
+static struct clk_hw *ath79_clk_register(struct device *dev, const char *name,
+ struct clk_hw *parent,
+ unsigned long rate)
+{
+ struct clk_parent_data pdata = { .hw = parent };
+
+ return devm_clk_hw_register_fixed_rate_parent_data(dev, name,
+ parent ? &pdata : NULL,
+ 0, rate);
+}
+
+static int ath79_clk_probe(struct platform_device *pdev)
+{
+ struct clk_hw *hws[ATH79_CLK_END];
+ const struct ath79_clk_soc_data *soc;
+ unsigned long rates[ATH79_OUT_NUM];
+ struct device *dev = &pdev->dev;
+ struct ath79_clk_regs regs = {};
+ struct clk_hw *ref;
+ int ret, i;
+
+ if (!ath79_clk_data)
+ return dev_err_probe(dev, -ENODEV,
+ "the early clock setup failed\n");
+
+ soc = device_get_match_data(dev);
+ ref = ath79_clk_data->hws[ATH79_CLK_REF];
+
+ regs.pll = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs.pll))
+ return PTR_ERR(regs.pll);
+
+ if (soc->has_srif) {
+ regs.srif = devm_ioremap(dev, AR934X_SRIF_BASE,
+ AR934X_SRIF_SIZE);
+ if (!regs.srif)
+ return -ENOMEM;
+ }
+
+ ret = ath79_get_rates(soc, ®s, clk_hw_get_rate(ref), rates);
+ if (ret)
+ return dev_err_probe(dev, ret, "invalid PLL setup\n");
+
+ hws[ATH79_CLK_REF] = ref;
+ hws[ATH79_CLK_CPU] = ath79_clk_data->hws[ATH79_CLK_CPU];
+ hws[ATH79_CLK_DDR] = ath79_clk_register(dev, "ddr", ref,
+ rates[ATH79_OUT_DDR]);
+ hws[ATH79_CLK_AHB] = ath79_clk_register(dev, "ahb", ref,
+ rates[ATH79_OUT_AHB]);
+ hws[ATH79_CLK_MDIO] = ref;
+ hws[ATH79_CLK_UART1] = ref;
+ hws[ATH79_CLK_PCIE] = ERR_PTR(-ENOENT);
+
+ if (soc->has_switch_clk) {
+ u32 ctrl = readl(regs.pll + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+
+ if (ctrl & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL)
+ hws[ATH79_CLK_MDIO] =
+ ath79_clk_register(dev, "mdio", NULL,
+ ATH79_SWITCH_CLK_RATE);
+
+ if (ctrl & AR934X_PLL_SWITCH_CLOCK_CONTROL_UART1_CLK_SEL)
+ hws[ATH79_CLK_UART1] =
+ ath79_clk_register(dev, "uart1", NULL,
+ ATH79_SWITCH_CLK_RATE);
+ }
+
+ if (soc->pcie)
+ hws[ATH79_CLK_PCIE] = ath79_pcie_pll_register(dev, regs.pll,
+ soc->pcie);
+
+ for (i = 0; i < ATH79_CLK_END; i++) {
+ if (IS_ERR(hws[i]) && PTR_ERR(hws[i]) != -ENOENT)
+ return dev_err_probe(dev, PTR_ERR(hws[i]),
+ "failed to register clock %d\n", i);
+ }
+
+ /*
+ * Hand the clocks to the provider registered early. Nothing can
+ * fail from here on, and the driver can't be unbound.
+ */
+ for (i = 0; i < ATH79_CLK_END; i++)
+ ath79_clk_data->hws[i] = hws[i];
+
+ return 0;
+}
+
+static struct platform_driver ath79_clk_driver = {
+ .probe = ath79_clk_probe,
+ .driver = {
+ .name = "ath79-clk",
+ .of_match_table = ath79_clk_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(ath79_clk_driver);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v2 6/6] MIPS: ath79: remove the old clock code
2026-11-10 1:36 [PATCH v2 0/6] clk: add a driver for the ath79 PLL controller Rosen Penev
` (4 preceding siblings ...)
2026-11-10 1:36 ` [PATCH v2 5/6] clk: add a driver for the Atheros/Qualcomm ath79 PLL controller Rosen Penev
@ 2026-11-10 1:36 ` Rosen Penev
5 siblings, 0 replies; 7+ messages in thread
From: Rosen Penev @ 2026-11-10 1:36 UTC (permalink / raw)
To: Thomas Bogendoerfer, Stephen Boyd, Brian Masney, Jerome Brunet,
Alban Bedel, Antony Pavlov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, linux-mips, linux-clk, devicetree
The clk-ath79 driver in drivers/clk has replaced arch/mips/ath79/clock.c,
which is no longer built. Remove it.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
arch/mips/ath79/Makefile | 3 -
arch/mips/ath79/clock.c | 626 ---------------------------------------
2 files changed, 629 deletions(-)
delete mode 100644 arch/mips/ath79/clock.c
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
index b78ffdc9b389..5df55b5e1c15 100644
--- a/arch/mips/ath79/Makefile
+++ b/arch/mips/ath79/Makefile
@@ -8,7 +8,4 @@
obj-y := prom.o setup.o common.o
-# replaced by the clk-ath79 driver
-obj-$(if $(CONFIG_COMMON_CLK_ATH79),,y) += clock.o
-
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c
deleted file mode 100644
index 85f747cf37a8..000000000000
--- a/arch/mips/ath79/clock.c
+++ /dev/null
@@ -1,626 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Atheros AR71XX/AR724X/AR913X common routines
- *
- * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
- * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
- *
- * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
- */
-
-#include <linux/kernel.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>
-
-#include <asm/mach-ath79/ath79.h>
-#include <asm/mach-ath79/ar71xx_regs.h>
-#include "common.h"
-
-static struct clk *clks[ATH79_CLK_END];
-static struct clk_onecell_data clk_data = {
- .clks = clks,
- .clk_num = ARRAY_SIZE(clks),
-};
-
-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 const char * __init ath79_clk_name(int type)
-{
- BUG_ON(type >= ARRAY_SIZE(clk_names) || !clk_names[type]);
- return clk_names[type];
-}
-
-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]);
-
- clks[type] = clk;
- clk_register_clkdev(clk, name, NULL);
-}
-
-static struct clk * __init ath79_set_clk(int type, unsigned long rate)
-{
- const char *name = ath79_clk_name(type);
- struct clk *clk;
-
- clk = clk_register_fixed_rate(NULL, name, NULL, 0, rate);
- __ath79_set_clk(type, name, clk);
- return clk;
-}
-
-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;
-
- clk = clk_register_fixed_factor(NULL, name, parent, 0, mult, div);
- __ath79_set_clk(type, name, clk);
- return clk;
-}
-
-static unsigned long __init ath79_get_ref_rate(void)
-{
- if (!clks[ATH79_CLK_REF])
- panic("ath79: no reference clock");
-
- return clk_get_rate(clks[ATH79_CLK_REF]);
-}
-
-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;
-
- ref_rate = ath79_get_ref_rate();
-
- pll = __raw_readl(pll_base + AR71XX_PLL_REG_CPU_CONFIG);
-
- div = ((pll >> AR71XX_PLL_FB_SHIFT) & AR71XX_PLL_FB_MASK) + 1;
- freq = div * ref_rate;
-
- div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
- cpu_rate = freq / div;
-
- div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
- ddr_rate = freq / div;
-
- div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
- ahb_rate = cpu_rate / div;
-
- 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 ar724x_clocks_init(void __iomem *pll_base)
-{
- u32 mult, div, ddr_div, ahb_div;
- u32 pll;
-
- ath79_get_ref_rate();
-
- pll = __raw_readl(pll_base + AR724X_PLL_REG_CPU_CONFIG);
-
- mult = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK);
- div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK) * 2;
-
- 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;
-
- 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 __iomem *pll_base)
-{
- u32 clock_ctrl;
- u32 ref_div;
- u32 ninit_mul;
- u32 out_div;
-
- u32 cpu_div;
- u32 ddr_div;
- u32 ahb_div;
-
- ath79_get_ref_rate();
-
- clock_ctrl = __raw_readl(pll_base + AR933X_PLL_CLOCK_CTRL_REG);
- if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
- ref_div = 1;
- ninit_mul = 1;
- out_div = 1;
-
- cpu_div = 1;
- ddr_div = 1;
- ahb_div = 1;
- } else {
- 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;
- ref_div = t;
-
- ninit_mul = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
- AR933X_PLL_CPU_CONFIG_NINT_MASK;
-
- t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
- AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
- if (t == 0)
- t = 1;
-
- out_div = (1 << t);
-
- cpu_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
- AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1;
-
- ddr_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
- AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1;
-
- ahb_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
- AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1;
- }
-
- 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,
- u32 frac, u32 out_div)
-{
- u64 t;
- u32 ret;
-
- t = ref;
- t *= nint;
- do_div(t, ref_div);
- ret = t;
-
- t = ref;
- t *= nfrac;
- do_div(t, ref_div * frac);
- ret += t;
-
- ret /= (1 << out_div);
- return ret;
-}
-
-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;
- void __iomem *dpll_base;
-
- dpll_base = ioremap(AR934X_SRIF_BASE, AR934X_SRIF_SIZE);
-
- ref_rate = ath79_get_ref_rate();
-
- pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL2_REG);
- if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
- out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) &
- AR934X_SRIF_DPLL2_OUTDIV_MASK;
- pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL1_REG);
- nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) &
- AR934X_SRIF_DPLL1_NINT_MASK;
- nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK;
- ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) &
- AR934X_SRIF_DPLL1_REFDIV_MASK;
- frac = 1 << 18;
- } else {
- 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) &
- AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
- nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
- AR934X_PLL_CPU_CONFIG_NINT_MASK;
- nfrac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
- AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
- frac = 1 << 6;
- }
-
- 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);
- if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
- out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) &
- AR934X_SRIF_DPLL2_OUTDIV_MASK;
- pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL1_REG);
- nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) &
- AR934X_SRIF_DPLL1_NINT_MASK;
- nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK;
- ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) &
- AR934X_SRIF_DPLL1_REFDIV_MASK;
- frac = 1 << 18;
- } else {
- 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) &
- AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
- nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
- AR934X_PLL_DDR_CONFIG_NINT_MASK;
- nfrac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
- AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
- frac = 1 << 10;
- }
-
- ddr_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
- nfrac, frac, out_div);
-
- 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)
- cpu_rate = ref_rate;
- else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL)
- cpu_rate = cpu_pll / (postdiv + 1);
- else
- 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)
- ddr_rate = ref_rate;
- else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL)
- ddr_rate = ddr_pll / (postdiv + 1);
- else
- 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)
- ahb_rate = ref_rate;
- else if (clk_ctrl & AR934X_PLL_CPU_DDR_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);
-
- 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 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;
-
- ref_rate = ath79_get_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;
-
- ref_rate = ath79_get_ref_rate();
-
- 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) &
- QCA955X_PLL_CPU_CONFIG_REFDIV_MASK;
- nint = (pll >> QCA955X_PLL_CPU_CONFIG_NINT_SHIFT) &
- QCA955X_PLL_CPU_CONFIG_NINT_MASK;
- frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
- QCA955X_PLL_CPU_CONFIG_NFRAC_MASK;
-
- cpu_pll = nint * ref_rate / ref_div;
- cpu_pll += frac * ref_rate / (ref_div * (1 << 6));
- cpu_pll /= (1 << out_div);
-
- 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) &
- QCA955X_PLL_DDR_CONFIG_REFDIV_MASK;
- nint = (pll >> QCA955X_PLL_DDR_CONFIG_NINT_SHIFT) &
- QCA955X_PLL_DDR_CONFIG_NINT_MASK;
- frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
- QCA955X_PLL_DDR_CONFIG_NFRAC_MASK;
-
- ddr_pll = nint * ref_rate / ref_div;
- ddr_pll += frac * ref_rate / (ref_div * (1 << 10));
- ddr_pll /= (1 << out_div);
-
- 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)
- cpu_rate = ref_rate;
- else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
- cpu_rate = ddr_pll / (postdiv + 1);
- else
- 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)
- ddr_rate = ref_rate;
- else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
- ddr_rate = cpu_pll / (postdiv + 1);
- else
- 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)
- ahb_rate = ref_rate;
- else if (clk_ctrl & QCA955X_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 qca956x_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, hfrac, lfrac, clk_ctrl, postdiv;
- u32 cpu_pll, ddr_pll;
-
- ref_rate = ath79_get_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);
-
- 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);
-
- clk_ctrl = __raw_readl(pll_base + QCA956X_PLL_CLK_CTRL_REG);
-
- postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
- QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
-
- 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);
-
- postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
- QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
-
- 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);
-
- postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
- QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
-
- 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);
-
- 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 ath79_clocks_init_dt(struct device_node *np)
-{
- struct clk *ref_clk;
- void __iomem *pll_base;
-
- /*
- * The board's crystal. Without a rate in the device tree, the arch
- * code registers it from the bootstrap pins.
- */
- ref_clk = of_clk_get(np, 0);
- if (IS_ERR(ref_clk))
- ref_clk = clk_get_sys(NULL, "ref");
- 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);
-}
-
-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);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread