summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-10-02 10:55:44 -0400
committerTom Rini <[email protected]>2023-10-02 10:55:44 -0400
commitac897385bbfa30cfdfb62ccf24acfcd4b274b2ff (patch)
treeae567980737beb24ca24e2ee8cfeaf6eb9e26e3f /drivers/clk
parent4459ed60cb1e0562bc5b40405e2b4b9bbf766d57 (diff)
parente29b932aa07fa0226d325b35d96cd4eea0370129 (diff)
Merge branch 'next'
Signed-off-by: Tom Rini <[email protected]>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Kconfig13
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/analogbits/wrpll-cln28hpc.c1
-rw-r--r--drivers/clk/clk-divider.c1
-rw-r--r--drivers/clk/clk-gate.c1
-rw-r--r--drivers/clk/clk-gpio.c66
-rw-r--r--drivers/clk/clk-hsdk-cgu.c1
-rw-r--r--drivers/clk/clk-mux.c1
-rw-r--r--drivers/clk/clk-uclass.c8
-rw-r--r--drivers/clk/clk_boston.c1
-rw-r--r--drivers/clk/clk_versal.c98
-rw-r--r--drivers/clk/imx/clk-pll14xx.c1
-rw-r--r--drivers/clk/rockchip/clk_rk3368.c1
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c1
14 files changed, 161 insertions, 34 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 29859cdfa15..bfd23a99046 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -83,6 +83,19 @@ config CLK_COMPOSITE_CCF
Enable this option if you want to (re-)use the Linux kernel's Common
Clock Framework [CCF] composite code in U-Boot's clock driver.
+config CLK_GPIO
+ bool "GPIO-controlled clock gate driver"
+ depends on CLK
+ help
+ Enable this option to add GPIO-controlled clock gate driver.
+
+config SPL_CLK_GPIO
+ bool "GPIO-controlled clock gate driver in SPL"
+ depends on SPL_CLK
+ help
+ Enable this option to add GPIO-controlled clock gate driver
+ in U-Boot SPL.
+
config CLK_BCM6345
bool "Clock controller driver for BCM6345"
depends on CLK && ARCH_BMIPS
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e22c8cf291f..26bf429acbc 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o
obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o
obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_GPIO) += clk-gpio.o
obj-y += analogbits/
obj-y += imx/
diff --git a/drivers/clk/analogbits/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c
index 776ead319ae..a3cb109d357 100644
--- a/drivers/clk/analogbits/wrpll-cln28hpc.c
+++ b/drivers/clk/analogbits/wrpll-cln28hpc.c
@@ -26,6 +26,7 @@
#include <linux/log2.h>
#include <linux/math64.h>
#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+#include <linux/printk.h>
/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
#define MIN_INPUT_FREQ 7000000
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6ab137a72be..2ad682b8fe2 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -28,6 +28,7 @@
#include <linux/log2.h>
#include <div64.h>
#include <clk.h>
+#include <linux/printk.h>
#include "clk.h"
#define UBOOT_DM_CLK_CCF_DIVIDER "ccf_clk_divider"
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index a8775c77dc2..cfd90b717e7 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -21,6 +21,7 @@
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/printk.h>
#include "clk.h"
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
new file mode 100644
index 00000000000..26d795b9783
--- /dev/null
+++ b/drivers/clk/clk-gpio.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Marek Vasut <[email protected]>
+ */
+
+#include <asm/gpio.h>
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+
+struct clk_gpio_priv {
+ struct gpio_desc enable;
+};
+
+static int clk_gpio_enable(struct clk *clk)
+{
+ struct clk_gpio_priv *priv = dev_get_priv(clk->dev);
+
+ dm_gpio_set_value(&priv->enable, 1);
+
+ return 0;
+}
+
+static int clk_gpio_disable(struct clk *clk)
+{
+ struct clk_gpio_priv *priv = dev_get_priv(clk->dev);
+
+ dm_gpio_set_value(&priv->enable, 0);
+
+ return 0;
+}
+
+const struct clk_ops clk_gpio_ops = {
+ .enable = clk_gpio_enable,
+ .disable = clk_gpio_disable,
+};
+
+static int clk_gpio_probe(struct udevice *dev)
+{
+ struct clk_gpio_priv *priv = dev_get_priv(dev);
+
+ return gpio_request_by_name(dev, "enable-gpios", 0,
+ &priv->enable, GPIOD_IS_OUT);
+}
+
+/*
+ * When implementing clk-mux-clock, use gpio_request_list_by_name
+ * and implement get_rate/set_rate/set_parent ops. This should be
+ * in a separate driver and with separate Kconfig option to enable
+ * that driver, since unlike Linux implementation, the U-Boot DM
+ * integration would be orthogonal to this driver.
+ */
+static const struct udevice_id clk_gpio_match[] = {
+ { .compatible = "gpio-gate-clock" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(gpio_gate_clock) = {
+ .name = "gpio_clock",
+ .id = UCLASS_CLK,
+ .of_match = clk_gpio_match,
+ .probe = clk_gpio_probe,
+ .priv_auto = sizeof(struct clk_gpio_priv),
+ .ops = &clk_gpio_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c
index e28543ef78b..85074f1b86e 100644
--- a/drivers/clk/clk-hsdk-cgu.c
+++ b/drivers/clk/clk-hsdk-cgu.c
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/arcregs.h>
+#include <linux/printk.h>
#include <dt-bindings/clock/snps,hsdk-cgu.h>
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 017f25f7a5a..f410518461e 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -36,6 +36,7 @@
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/printk.h>
#include "clk.h"
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index dc3e9d6a261..f186fcbcdb8 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -329,7 +329,13 @@ static int clk_set_default_rates(struct udevice *dev,
dev_dbg(dev,
"could not get assigned clock %d (err = %d)\n",
index, ret);
- continue;
+ /* Skip if it is empty */
+ if (ret == -ENOENT) {
+ ret = 0;
+ continue;
+ }
+
+ return ret;
}
/* This is clk provider device trying to program itself
diff --git a/drivers/clk/clk_boston.c b/drivers/clk/clk_boston.c
index 2e81777b703..4bcf9117551 100644
--- a/drivers/clk/clk_boston.c
+++ b/drivers/clk/clk_boston.c
@@ -10,6 +10,7 @@
#include <regmap.h>
#include <syscon.h>
#include <linux/bitops.h>
+#include <linux/printk.h>
struct clk_boston {
struct regmap *regmap;
diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c
index b3b33331235..2e004beca2f 100644
--- a/drivers/clk/clk_versal.c
+++ b/drivers/clk/clk_versal.c
@@ -68,6 +68,13 @@
#define CLOCK_NODE_TYPE_DIV 4
#define CLOCK_NODE_TYPE_GATE 6
+#define PM_CLK_REF_CLK (0x830c06aU)
+#define PM_CLK_PL_ALT_REF_CLK (0x830c06bU)
+#define PM_CLK_MUXED_IRO (0x830c06cU)
+#define PM_CLK_EMIO (0x830c071U)
+
+#define TOPOLOGY_TYPE_FIXEDFACTOR 0x3
+
enum clk_type {
CLK_TYPE_OUTPUT,
CLK_TYPE_EXTERNAL,
@@ -365,48 +372,37 @@ static u32 versal_clock_set_div(u32 clk_id, u32 div)
return div;
}
-static u64 versal_clock_ref(u32 clk_id)
+static u64 versal_clock_get_ref_rate(u32 clk_id)
{
- u32 ret_payload[PAYLOAD_ARG_CNT];
- int ref;
-
- xilinx_pm_request(PM_CLOCK_GETPARENT, clk_id, 0, 0, 0, ret_payload);
- ref = ret_payload[0];
- if (!(ref & 1))
+ if (clk_id == PM_CLK_REF_CLK || clk_id == PM_CLK_MUXED_IRO || clk_id == PM_CLK_EMIO)
return ref_clk;
- if (ref & 2)
+ else if (clk_id == PM_CLK_PL_ALT_REF_CLK)
return pl_alt_ref_clk;
- return 0;
+ else
+ return 0;
}
-static u64 versal_clock_get_pll_rate(u32 clk_id)
+static int versal_clock_get_fixed_factor_rate(u32 clock_id, u32 parent_id)
{
+ struct versal_pm_query_data qdata = {0};
u32 ret_payload[PAYLOAD_ARG_CNT];
- u32 fbdiv;
- u32 res;
- u32 frac;
- u64 freq;
- u32 parent_rate, parent_id;
- u32 id = clk_id & 0xFFF;
+ u32 mult, div;
+ u32 parent_rate;
+ int ret;
- xilinx_pm_request(PM_CLOCK_GETSTATE, clk_id, 0, 0, 0, ret_payload);
- res = ret_payload[1];
- if (!res) {
- printf("0%x PLL not enabled\n", clk_id);
- return 0;
- }
+ qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
+ qdata.arg1 = clock_id;
- parent_id = clock[clock[id].parent[0].id].clk_id;
- parent_rate = versal_clock_ref(parent_id);
+ ret = versal_pm_query(qdata, ret_payload);
+ if (ret)
+ return ret;
- xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, ret_payload);
- fbdiv = ret_payload[1];
- xilinx_pm_request(PM_CLOCK_PLL_GETPARAM, clk_id, 2, 0, 0, ret_payload);
- frac = ret_payload[1];
+ mult = ret_payload[1];
+ div = ret_payload[2];
- freq = (fbdiv * parent_rate) >> (1 << frac);
+ parent_rate = versal_clock_get_ref_rate(parent_id);
+ return parent_rate * mult / div;
- return freq;
}
static u32 versal_clock_mux(u32 clk_id)
@@ -437,6 +433,37 @@ static u32 versal_clock_get_parentid(u32 clk_id)
return clock[clock[id].parent[parent_id].id].clk_id;
}
+static u64 versal_clock_get_pll_rate(u32 clk_id)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ u32 fbdiv;
+ u32 res;
+ u32 frac;
+ u64 freq;
+ u32 parent_rate, parent_id, parent_ref_clk_id;
+ u32 id = clk_id & 0xFFF;
+
+ xilinx_pm_request(PM_CLOCK_GETSTATE, clk_id, 0, 0, 0, ret_payload);
+ res = ret_payload[1];
+ if (!res) {
+ printf("0%x PLL not enabled\n", clk_id);
+ return 0;
+ }
+
+ parent_id = clock[clock[id].parent[0].id].clk_id;
+ parent_ref_clk_id = versal_clock_get_parentid(parent_id);
+ parent_rate = versal_clock_get_ref_rate(parent_ref_clk_id);
+
+ xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, ret_payload);
+ fbdiv = ret_payload[1];
+ xilinx_pm_request(PM_CLOCK_PLL_GETPARAM, clk_id, 2, 0, 0, ret_payload);
+ frac = ret_payload[1];
+
+ freq = (fbdiv * parent_rate) >> (1 << frac);
+
+ return freq;
+}
+
static u32 versal_clock_gate(u32 clk_id)
{
u32 id = clk_id & 0xFFF;
@@ -479,14 +506,19 @@ static u64 versal_clock_calc(u32 clk_id)
u32 parent_id;
u64 clk_rate;
u32 div;
+ struct clock_topology topology;
if (versal_clock_pll(clk_id, &clk_rate))
return clk_rate;
parent_id = versal_clock_get_parentid(clk_id);
if (((parent_id >> NODE_SUBCLASS_SHIFT) &
- NODE_CLASS_MASK) == NODE_SUBCLASS_CLOCK_REF)
- return versal_clock_ref(clk_id);
+ NODE_CLASS_MASK) == NODE_SUBCLASS_CLOCK_REF) {
+ topology = clock[clk_id & 0x3FF].node[0];
+ if (topology.type == TOPOLOGY_TYPE_FIXEDFACTOR)
+ return versal_clock_get_fixed_factor_rate(clk_id, parent_id);
+ return versal_clock_get_ref_rate(parent_id);
+ }
if (!parent_id)
return 0;
@@ -505,7 +537,7 @@ static int versal_clock_get_rate(u32 clk_id, u64 *clk_rate)
{
if (((clk_id >> NODE_SUBCLASS_SHIFT) &
NODE_CLASS_MASK) == NODE_SUBCLASS_CLOCK_REF)
- *clk_rate = versal_clock_ref(clk_id);
+ *clk_rate = versal_clock_get_ref_rate(clk_id);
if (versal_clock_pll(clk_id, clk_rate))
return 0;
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index b93c0bc64e7..1cb685ee9ab 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -18,6 +18,7 @@
#include <linux/iopoll.h>
#include <clk.h>
#include <div64.h>
+#include <linux/printk.h>
#include "clk.h"
diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c
index a47c431cf5f..3406ff592e1 100644
--- a/drivers/clk/rockchip/clk_rk3368.c
+++ b/drivers/clk/rockchip/clk_rk3368.c
@@ -23,6 +23,7 @@
#include <dm/lists.h>
#include <dt-bindings/clock/rk3368-cru.h>
#include <linux/delay.h>
+#include <linux/printk.h>
#include <linux/stringify.h>
#if CONFIG_IS_ENABLED(OF_PLATDATA)
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index f748fb5189e..c37e8a53a26 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -24,6 +24,7 @@
#include <dt-bindings/clock/rk3399-cru.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/printk.h>
DECLARE_GLOBAL_DATA_PTR;