From 92d5f99633e4d0a33ea1f22e28674440ddcd7072 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 14 Aug 2023 01:51:27 +0200 Subject: clk: Add GPIO-controlled clock gate driver Add driver which implements GPIO-controlled clock. The GPIO is used as a gate to enable/disable the clock. This matches linux clk-gpio.c driver, however this does not implement the GPIO mux part, which in U-Boot DM would be better fit in separate driver. Signed-off-by: Marek Vasut Reviewed-by: Sean Anderson --- drivers/clk/Kconfig | 13 ++++++++++ drivers/clk/Makefile | 1 + drivers/clk/clk-gpio.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 drivers/clk/clk-gpio.c (limited to 'drivers/clk') 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/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 + */ + +#include +#include +#include +#include + +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, +}; -- cgit v1.2.3 From 99b46477e3495f819f6826d11470d46f12a4f9f7 Mon Sep 17 00:00:00 2001 From: Ashok Reddy Soma Date: Wed, 30 Aug 2023 10:31:42 +0200 Subject: clk: Dont return error when assigned-clocks is empty or missing There is a chance that assigned-clock-rates is given and assigned-clocks could be empty. Dont return error in that case, because the probe of the corresponding driver will not be called at all if this fails. Better to continue to look for it and return 0. Signed-off-by: Ashok Reddy Soma Reviewed-by: Tom Rini Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/a9a9d853e0ac396cd9b3577cce26279a75765711.1693384296.git.michal.simek@amd.com --- drivers/clk/clk-uclass.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/clk') 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 -- cgit v1.2.3 From c7cce2606d252a83e72655bb595d7ff4a267615c Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Tue, 12 Sep 2023 09:00:55 +0530 Subject: clk: versal: Fix the function versal_clock_ref For reference clocks, PM_CLK_GET_PARENT call is not allowed. PM_CLK_GET_PARENT only allowed for MUX clocks. Rename the versal_clock_ref() with versal_clock_get_ref_rate() for better readability. Fix the versal_clock_get_ref_rate function by passing the parent_id, and check whether the parent_id belongs to ref_clk or pl_alt_ref_clk. Also adding the function versal_clock_get_fixed_factor_rate() if the clk_id belongs to the fixed factor clock. Signed-off-by: Venkatesh Yadav Abbarapu Link: https://lore.kernel.org/r/20230912033055.2549-1-venkatesh.abbarapu@amd.com Signed-off-by: Michal Simek --- drivers/clk/clk_versal.c | 98 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 33 deletions(-) (limited to 'drivers/clk') 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; -- cgit v1.2.3 From 1e94b46f73cedcebbff73799203f3266c5b28d90 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 14 Sep 2023 18:21:46 -0600 Subject: common: Drop linux/printk.h from common header This old patch was marked as deferred. Bring it back to life, to continue towards the removal of common.h Move this out of the common header and include it only where needed. Signed-off-by: Simon Glass --- drivers/clk/analogbits/wrpll-cln28hpc.c | 1 + drivers/clk/clk-divider.c | 1 + drivers/clk/clk-gate.c | 1 + drivers/clk/clk-hsdk-cgu.c | 1 + drivers/clk/clk-mux.c | 1 + drivers/clk/clk_boston.c | 1 + drivers/clk/imx/clk-pll14xx.c | 1 + drivers/clk/rockchip/clk_rk3368.c | 1 + drivers/clk/rockchip/clk_rk3399.c | 1 + 9 files changed, 9 insertions(+) (limited to 'drivers/clk') 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 #include #include +#include /* 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 #include #include +#include #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 #include #include +#include #include "clk.h" 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 #include #include +#include #include 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 #include #include +#include #include "clk.h" 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 #include #include +#include struct clk_boston { struct regmap *regmap; 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 #include #include +#include #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 #include #include +#include #include #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 #include #include +#include DECLARE_GLOBAL_DATA_PTR; -- cgit v1.2.3