From 9538c7fac04625000b64f3212348712498b443be Mon Sep 17 00:00:00 2001 From: FUKAUMI Naoki Date: Mon, 25 Aug 2025 15:31:50 +0000 Subject: [PATCH] generic: 6.12: backport gated-fixed-clk driver Backport gated-fixed-clk driver from Linux v6.13. This is needed to fix a PCIe controller probe hang on the Radxa ROCK 5 ITX. Signed-off-by: FUKAUMI Naoki Link: https://github.com/openwrt/openwrt/pull/19867 Signed-off-by: Hauke Mehrtens --- ...ks-add-binding-for-gated-fixed-clock.patch | 82 +++++++ ...ate-documentation-for-gpio-gate-cloc.patch | 27 +++ ...e-dev_err_probe-for-gpio-get-failure.patch | 44 ++++ ...io-add-driver-for-gated-fixed-clocks.patch | 229 ++++++++++++++++++ 4 files changed, 382 insertions(+) create mode 100644 target/linux/generic/backport-6.12/801-01-v6.13-dt-bindings-clocks-add-binding-for-gated-fixed-clock.patch create mode 100644 target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch create mode 100644 target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch create mode 100644 target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch diff --git a/target/linux/generic/backport-6.12/801-01-v6.13-dt-bindings-clocks-add-binding-for-gated-fixed-clock.patch b/target/linux/generic/backport-6.12/801-01-v6.13-dt-bindings-clocks-add-binding-for-gated-fixed-clock.patch new file mode 100644 index 0000000000..f5ab8a0e3b --- /dev/null +++ b/target/linux/generic/backport-6.12/801-01-v6.13-dt-bindings-clocks-add-binding-for-gated-fixed-clock.patch @@ -0,0 +1,82 @@ +From a4a7cbe36623ffaabbae413c0eacf40d033db71f Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:07 +0200 +Subject: dt-bindings: clocks: add binding for gated-fixed-clocks + +In contrast to fixed clocks that are described as ungateable, boards +sometimes use additional oscillators for things like PCIe reference +clocks, that need actual supplies to get enabled and enable-gpios to be +toggled for them to work. + +This adds a binding for such oscillators that are not configurable +themself, but need to handle supplies for them to work. + +In schematics they often can be seen as + + ---------------- +Enable - | 100MHz,3.3V, | - VDD + | 3225 | + GND - | | - OUT + ---------------- + +or similar. The enable pin might be separate but can also just be tied +to the vdd supply, hence it is optional in the binding. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Rob Herring (Arm) +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20240906082511.2963890-2-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- /dev/null ++++ b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml +@@ -0,0 +1,49 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/clock/gated-fixed-clock.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Gated Fixed clock ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ const: gated-fixed-clock ++ ++ "#clock-cells": ++ const: 0 ++ ++ clock-frequency: true ++ ++ clock-output-names: ++ maxItems: 1 ++ ++ enable-gpios: ++ description: ++ Contains a single GPIO specifier for the GPIO that enables and disables ++ the oscillator. ++ maxItems: 1 ++ ++ vdd-supply: ++ description: handle of the regulator that provides the supply voltage ++ ++required: ++ - compatible ++ - "#clock-cells" ++ - clock-frequency ++ - vdd-supply ++ ++additionalProperties: false ++ ++examples: ++ - | ++ clock-1000000000 { ++ compatible = "gated-fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <1000000000>; ++ vdd-supply = <®_vdd>; ++ }; ++... diff --git a/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch b/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch new file mode 100644 index 0000000000..99e41a1e99 --- /dev/null +++ b/target/linux/generic/backport-6.12/801-02-v6.13-clk-clk-gpio-update-documentation-for-gpio-gate-cloc.patch @@ -0,0 +1,27 @@ +From 6cb137c7e99f8307f1f0fcccb1896f2d3b0651d3 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:08 +0200 +Subject: clk: clk-gpio: update documentation for gpio-gate clock + +The main documentation block seems to be from a time before the driver +handled sleeping and non-sleeping gpios and with that change it seems +updating the doc was overlooked. So do that now. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-3-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -22,8 +22,9 @@ + * DOC: basic gpio gated clock which can be enabled and disabled + * with gpio output + * Traits of this clock: +- * prepare - clk_(un)prepare only ensures parent is (un)prepared +- * enable - clk_enable and clk_disable are functional & control gpio ++ * prepare - clk_(un)prepare are functional and control a gpio that can sleep ++ * enable - clk_enable and clk_disable are functional & control ++ * non-sleeping gpio + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ diff --git a/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch b/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch new file mode 100644 index 0000000000..1982bb365e --- /dev/null +++ b/target/linux/generic/backport-6.12/801-03-v6.13-clk-clk-gpio-use-dev_err_probe-for-gpio-get-failure.patch @@ -0,0 +1,44 @@ +From 36abe81d9c3fa200a57ef2363e93a2991e387e19 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:09 +0200 +Subject: clk: clk-gpio: use dev_err_probe for gpio-get failure + +This is a real driver and dev_err_probe will hide the distinction between +EPROBE_DEFER and other errors automatically, so there is no need to +open-code this. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-4-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -200,7 +200,6 @@ static int gpio_clk_driver_probe(struct + struct gpio_desc *gpiod; + struct clk_hw *hw; + bool is_mux; +- int ret; + + is_mux = of_device_is_compatible(node, "gpio-mux-clock"); + +@@ -212,17 +211,9 @@ static int gpio_clk_driver_probe(struct + + gpio_name = is_mux ? "select" : "enable"; + gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW); +- if (IS_ERR(gpiod)) { +- ret = PTR_ERR(gpiod); +- if (ret == -EPROBE_DEFER) +- pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n", +- node, __func__); +- else +- pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n", +- node, __func__, +- gpio_name); +- return ret; +- } ++ if (IS_ERR(gpiod)) ++ return dev_err_probe(dev, PTR_ERR(gpiod), ++ "Can't get '%s' named GPIO property\n", gpio_name); + + if (is_mux) + hw = clk_hw_register_gpio_mux(dev, gpiod); diff --git a/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch b/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch new file mode 100644 index 0000000000..44da746fdc --- /dev/null +++ b/target/linux/generic/backport-6.12/801-04-v6.13-clk-clk-gpio-add-driver-for-gated-fixed-clocks.patch @@ -0,0 +1,229 @@ +From 4940071d962827467f7297be3b874c96186ca0b7 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Sep 2024 10:25:10 +0200 +Subject: clk: clk-gpio: add driver for gated-fixed-clocks + +In contrast to fixed clocks that are described as ungateable, boards +sometimes use additional oscillators for things like PCIe reference +clocks, that need actual supplies to get enabled and enable-gpios to be +toggled for them to work. + +This adds a driver for those generic gated-fixed-clocks +that can show up in schematics looking like + + ---------------- +Enable - | 100MHz,3.3V, | - VDD + | 3225 | + GND - | | - OUT + ---------------- + +The new driver gets grouped together with the existing gpio-gate and +gpio-mux, as it for one re-uses a lot of the gpio-gate functions +and also in its core it's just another gpio-controlled clock, just +with a fixed rate and a regulator-supply added in. + +The regulator-API provides function stubs for the !CONFIG_REGULATOR case, +so no special handling is necessary. + +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20240906082511.2963890-5-heiko@sntech.de +Signed-off-by: Stephen Boyd + +--- a/drivers/clk/clk-gpio.c ++++ b/drivers/clk/clk-gpio.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + /** + * DOC: basic gpio gated clock which can be enabled and disabled +@@ -239,3 +240,187 @@ static struct platform_driver gpio_clk_d + }, + }; + builtin_platform_driver(gpio_clk_driver); ++ ++/** ++ * DOC: gated fixed clock, controlled with a gpio output and a regulator ++ * Traits of this clock: ++ * prepare - clk_prepare and clk_unprepare are function & control regulator ++ * optionally a gpio that can sleep ++ * enable - clk_enable and clk_disable are functional & control gpio ++ * rate - rate is fixed and set on clock registration ++ * parent - fixed clock is a root clock and has no parent ++ */ ++ ++/** ++ * struct clk_gated_fixed - Gateable fixed rate clock ++ * @clk_gpio: instance of clk_gpio for gate-gpio ++ * @supply: supply regulator ++ * @rate: fixed rate ++ */ ++struct clk_gated_fixed { ++ struct clk_gpio clk_gpio; ++ struct regulator *supply; ++ unsigned long rate; ++}; ++ ++#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio) ++ ++static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return to_clk_gated_fixed(to_clk_gpio(hw))->rate; ++} ++ ++static int clk_gated_fixed_prepare(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return 0; ++ ++ return regulator_enable(clk->supply); ++} ++ ++static void clk_gated_fixed_unprepare(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return; ++ ++ regulator_disable(clk->supply); ++} ++ ++static int clk_gated_fixed_is_prepared(struct clk_hw *hw) ++{ ++ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); ++ ++ if (!clk->supply) ++ return true; ++ ++ return regulator_is_enabled(clk->supply); ++} ++ ++/* ++ * Fixed gated clock with non-sleeping gpio. ++ * ++ * Prepare operation turns on the supply regulator ++ * and the enable operation switches the enable-gpio. ++ */ ++static const struct clk_ops clk_gated_fixed_ops = { ++ .prepare = clk_gated_fixed_prepare, ++ .unprepare = clk_gated_fixed_unprepare, ++ .is_prepared = clk_gated_fixed_is_prepared, ++ .enable = clk_gpio_gate_enable, ++ .disable = clk_gpio_gate_disable, ++ .is_enabled = clk_gpio_gate_is_enabled, ++ .recalc_rate = clk_gated_fixed_recalc_rate, ++}; ++ ++static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw) ++{ ++ int ret; ++ ++ ret = clk_gated_fixed_prepare(hw); ++ if (ret) ++ return ret; ++ ++ ret = clk_sleeping_gpio_gate_prepare(hw); ++ if (ret) ++ clk_gated_fixed_unprepare(hw); ++ ++ return ret; ++} ++ ++static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw) ++{ ++ clk_gated_fixed_unprepare(hw); ++ clk_sleeping_gpio_gate_unprepare(hw); ++} ++ ++/* ++ * Fixed gated clock with non-sleeping gpio. ++ * ++ * Enabling the supply regulator and switching the enable-gpio happens ++ * both in the prepare step. ++ * is_prepared only needs to check the gpio state, as toggling the ++ * gpio is the last step when preparing. ++ */ ++static const struct clk_ops clk_sleeping_gated_fixed_ops = { ++ .prepare = clk_sleeping_gated_fixed_prepare, ++ .unprepare = clk_sleeping_gated_fixed_unprepare, ++ .is_prepared = clk_sleeping_gpio_gate_is_prepared, ++ .recalc_rate = clk_gated_fixed_recalc_rate, ++}; ++ ++static int clk_gated_fixed_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct clk_gated_fixed *clk; ++ const struct clk_ops *ops; ++ const char *clk_name; ++ u32 rate; ++ int ret; ++ ++ clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); ++ if (!clk) ++ return -ENOMEM; ++ ++ ret = device_property_read_u32(dev, "clock-frequency", &rate); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to get clock-frequency\n"); ++ clk->rate = rate; ++ ++ ret = device_property_read_string(dev, "clock-output-names", &clk_name); ++ if (ret) ++ clk_name = fwnode_get_name(dev->fwnode); ++ ++ clk->supply = devm_regulator_get_optional(dev, "vdd"); ++ if (IS_ERR(clk->supply)) { ++ if (PTR_ERR(clk->supply) != -ENODEV) ++ return dev_err_probe(dev, PTR_ERR(clk->supply), ++ "Failed to get regulator\n"); ++ clk->supply = NULL; ++ } ++ ++ clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(clk->clk_gpio.gpiod)) ++ return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod), ++ "Failed to get gpio\n"); ++ ++ if (gpiod_cansleep(clk->clk_gpio.gpiod)) ++ ops = &clk_sleeping_gated_fixed_ops; ++ else ++ ops = &clk_gated_fixed_ops; ++ ++ clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0); ++ ++ /* register the clock */ ++ ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to register clock\n"); ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, ++ &clk->clk_gpio.hw); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to register clock provider\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id gated_fixed_clk_match_table[] = { ++ { .compatible = "gated-fixed-clock" }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver gated_fixed_clk_driver = { ++ .probe = clk_gated_fixed_probe, ++ .driver = { ++ .name = "gated-fixed-clk", ++ .of_match_table = gated_fixed_clk_match_table, ++ }, ++}; ++builtin_platform_driver(gated_fixed_clk_driver); -- 2.30.2