linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree
@ 2022-12-31 10:47 Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 01/11] clk: imx: add structure to extend register accesses Dario Binacchi
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Adam Ford,
	Fabio Estevam, Krzysztof Kozlowski, Li Jun, Lucas Stach,
	Marek Vasut, Markus Niebel, Michael Turquette, NXP Linux Team,
	Pengutronix Kernel Team, Rob Herring, Sascha Hauer, Shawn Guo,
	Stephen Boyd, devicetree, linux-arm-kernel, linux-clk

The idea for this series was born back from Dublin (ELCE 2022) after
having attended the talk entitled "Updating and Modernizing Clock
Drivers" held by Chen-Yu Tsai and the availability of a board with
imx8mn SOC.

This series aims to setup all imx8mn's clocks from the device tree and
remove the legacy setup code with hardwired parameters.

I am well aware that the series lacks patches for the DT bindings. The
effort up to this point has been important and so I thought I'd ask for
feedback from the community before proceeding to implement them. If it
is positive I will add the DT binding patches starting from version 2.

The series has been tested on the BSH SystemMaster (SMM) S2 board:
https://www.apertis.org/reference_hardware/imx8mn_bsh_smm_s2pro_setup



Dario Binacchi (11):
  clk: imx: add structure to extend register accesses
  clk: imx: add clk_hw based API imx_get_clk_hw_from_dt()
  clk: imx8mn: add gate driver
  clk: imx8mn: add mux driver
  clk: imx8mn: add divider driver
  clk: imx: pll14xx: add device tree support
  clk: imx: composite-8m: add device tree support
  clk: imx: gate2: add device tree support
  clk: imx: cpu: add device tree support
  arm64: dts: imx8mn: add dumy clock
  arm64: dts: imx8mn: add clocks description

 .../boot/dts/freescale/imx8mn-clocks.dtsi     | 1885 +++++++++++++++++
 arch/arm64/boot/dts/freescale/imx8mn.dtsi     |   51 +-
 drivers/clk/imx/Makefile                      |    3 +
 drivers/clk/imx/clk-composite-8m.c            |   83 +
 drivers/clk/imx/clk-cpu.c                     |   54 +
 drivers/clk/imx/clk-divider.c                 |  235 ++
 drivers/clk/imx/clk-gate.c                    |  156 ++
 drivers/clk/imx/clk-gate2.c                   |   86 +
 drivers/clk/imx/clk-imx8mn.c                  |  716 ++-----
 drivers/clk/imx/clk-mux.c                     |  258 +++
 drivers/clk/imx/clk-pll14xx.c                 |  220 +-
 drivers/clk/imx/clk.c                         |   21 +
 drivers/clk/imx/clk.h                         |   15 +
 13 files changed, 3176 insertions(+), 607 deletions(-)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-clocks.dtsi
 create mode 100644 drivers/clk/imx/clk-divider.c
 create mode 100644 drivers/clk/imx/clk-gate.c
 create mode 100644 drivers/clk/imx/clk-mux.c

-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC PATCH 01/11] clk: imx: add structure to extend register accesses
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 02/11] clk: imx: add clk_hw based API imx_get_clk_hw_from_dt() Dario Binacchi
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The imx_clk_reg structure allows accessing both registers that belong to
specific modules and those that are registered in syscon through the use
of the regmap API.
This is a preparation patch for the upcoming support to setup clocks
directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 689b3ad927c0..86538c990a0d 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -89,6 +89,18 @@ struct imx_fracn_gppll_clk {
 	int flags;
 };
 
+/**
+ * struct imx_clk_reg - imx register declaration
+ * @base: the register base address
+ * @regmap: the register map
+ * @offset: the offset within @base or @regmap
+ */
+struct imx_clk_reg {
+	void __iomem *base;
+	struct regmap *regmap;
+	u16 offset;
+};
+
 struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
 				   const struct imx_fracn_gppll_clk *pll_clk);
 
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 02/11] clk: imx: add clk_hw based API imx_get_clk_hw_from_dt()
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 01/11] clk: imx: add structure to extend register accesses Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 03/11] clk: imx8mn: add gate driver Dario Binacchi
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

Clock providers are recommended to use the struct clk_hw based API, so
add an IMX provider helper to get clk_hw from device tree node name.

This is a preparation patch for the upcoming support to setup clocks
directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk.c | 21 +++++++++++++++++++++
 drivers/clk/imx/clk.h |  3 +++
 2 files changed, 24 insertions(+)

diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
index b636cc099d96..6ae122ccd83e 100644
--- a/drivers/clk/imx/clk.c
+++ b/drivers/clk/imx/clk.c
@@ -68,6 +68,27 @@ void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
 }
 EXPORT_SYMBOL_GPL(imx_check_clk_hws);
 
+struct clk_hw *imx_get_clk_hw_from_dt(struct device_node *np,
+				      const char *name)
+{
+	struct of_phandle_args clkspec;
+	struct clk *clk;
+
+	clkspec.np = of_find_node_by_name(np, name);
+	if (clkspec.np) {
+		clk = of_clk_get_from_provider(&clkspec);
+		if (!IS_ERR(clk)) {
+			pr_debug("%s: got %s clock\n", __func__, name);
+			of_node_put(clkspec.np);
+			return __clk_get_hw(clk);
+		}
+	}
+
+	pr_err("%s: failed to %s clock\n", __func__, name);
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(imx_get_clk_hw_from_dt);
+
 static struct clk *imx_obtain_fixed_clock_from_dt(const char *name)
 {
 	struct of_phandle_args phandle;
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 86538c990a0d..a0e6b8357eb7 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -294,6 +294,9 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
 		u8 clk_gate_flags, spinlock_t *lock,
 		unsigned int *share_count);
 
+struct clk_hw *imx_get_clk_hw_from_dt(struct device_node *np,
+				      const char *name);
+
 struct clk * imx_obtain_fixed_clock(
 			const char *name, unsigned long rate);
 
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 03/11] clk: imx8mn: add gate driver
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 01/11] clk: imx: add structure to extend register accesses Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 02/11] clk: imx: add clk_hw based API imx_get_clk_hw_from_dt() Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 04/11] clk: imx8mn: add mux driver Dario Binacchi
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch adds support for imx8mn gate clocks to be initialized directly
from the device tree. Currently all i.MX gate clocks are initialized by
legacy code with hardwired parameters. This approach has generated a
proliferation of setup functions with unclear names:

git grep "#define imx_clk_hw_gate" drivers/clk/imx/clk.h
drivers/clk/imx/clk.h:#define imx_clk_hw_gate(name, parent, reg, shift) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate2(name, parent, reg, shift) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate_dis(name, parent, reg, shift) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate_dis_flags(name, parent, reg, shift, flags) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate_flags(name, parent, reg, shift, flags) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate2_flags(name, parent, reg, shift, flags) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate2_shared(name, parent, reg, shift, shared_count) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate2_shared2(name, parent, reg, shift, shared_count) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate3(name, parent, reg, shift) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate3_flags(name, parent, reg, shift, flags) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate4(name, parent, reg, shift) \
drivers/clk/imx/clk.h:#define imx_clk_hw_gate4_flags(name, parent, reg, shift, flags) \

So, let's start with this specific clock driver and hope that other
variants can be handled in the future, causing the legacy code to be
removed.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/Makefile   |   1 +
 drivers/clk/imx/clk-gate.c | 156 +++++++++++++++++++++++++++++++++++++
 2 files changed, 157 insertions(+)
 create mode 100644 drivers/clk/imx/clk-gate.c

diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index e8aacb0ee6ac..72e1f08d49dc 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -11,6 +11,7 @@ mxc-clk-objs += clk-divider-gate.o
 mxc-clk-objs += clk-fixup-div.o
 mxc-clk-objs += clk-fixup-mux.o
 mxc-clk-objs += clk-frac-pll.o
+mxc-clk-objs += clk-gate.o
 mxc-clk-objs += clk-gate2.o
 mxc-clk-objs += clk-gate-93.o
 mxc-clk-objs += clk-gate-exclusive.o
diff --git a/drivers/clk/imx/clk-gate.c b/drivers/clk/imx/clk-gate.c
new file mode 100644
index 000000000000..841ff9a37f30
--- /dev/null
+++ b/drivers/clk/imx/clk-gate.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Amarula Solutions
+ *
+ * Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include "clk.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define to_clk_imx_gate(_hw) container_of(_hw, struct clk_imx_gate, hw)
+
+struct clk_imx_gate {
+	struct clk_hw hw;
+	struct imx_clk_reg reg;
+	u32 enable_mask;
+};
+
+static int imx_clk_gate_enable(struct clk_hw *hw)
+{
+	struct clk_imx_gate *gate = to_clk_imx_gate(hw);
+	struct imx_clk_reg *reg = &gate->reg;
+
+	return regmap_update_bits(reg->regmap, reg->offset, gate->enable_mask,
+				  gate->enable_mask);
+}
+
+static void imx_clk_gate_disable(struct clk_hw *hw)
+{
+	struct clk_imx_gate *gate = to_clk_imx_gate(hw);
+	struct imx_clk_reg *reg = &gate->reg;
+
+	regmap_update_bits(reg->regmap, reg->offset, gate->enable_mask, 0);
+}
+
+static int imx_clk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct clk_imx_gate *gate = to_clk_imx_gate(hw);
+	struct imx_clk_reg *reg = &gate->reg;
+	unsigned int val;
+
+	if (regmap_read(reg->regmap, reg->offset, &val))
+		return -EIO;
+
+	return !!(val & gate->enable_mask);
+}
+
+const struct clk_ops imx_clk_gate_ops = {
+	.enable	= &imx_clk_gate_enable,
+	.disable = &imx_clk_gate_disable,
+	.is_enabled = &imx_clk_gate_is_enabled,
+};
+
+static void imx_clk_hw_unregister_gate(struct clk_hw *hw)
+{
+	struct clk_imx_gate *gate = to_clk_imx_gate(hw);
+
+	clk_hw_unregister(hw);
+	kfree(gate);
+}
+
+static struct clk_hw *imx_clk_hw_register_gate(struct device_node *node,
+					       const char *name,
+					       unsigned long flags,
+					       struct imx_clk_reg *reg,
+					       u8 enable_bit)
+{
+	struct clk_parent_data pdata = { .index = 0 };
+	struct clk_init_data init = { NULL };
+	struct clk_imx_gate *gate;
+	struct clk_hw *hw;
+	int ret;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = flags;
+	init.ops = &imx_clk_gate_ops;
+	init.parent_data = &pdata;
+	init.num_parents = 1;
+
+	memcpy(&gate->reg, reg, sizeof(*reg));
+	gate->enable_mask = BIT(enable_bit);
+	gate->hw.init = &init;
+
+	hw = &gate->hw;
+	ret = of_clk_hw_register(node, hw);
+	if (ret) {
+		kfree(gate);
+		return ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+/**
+ * of_imx_gate_clk_setup() - Setup function for imx gate clock
+ * @node:	device node for the clock
+ */
+static void __init of_imx_gate_clk_setup(struct device_node *node)
+{
+	struct clk_hw *hw;
+	struct imx_clk_reg reg;
+	const char *name = node->name;
+	u8 enable_bit = 0;
+	u32 val;
+
+	reg.regmap = syscon_regmap_lookup_by_phandle(node, "fsl,anatop");
+	if (IS_ERR(reg.regmap)) {
+		pr_err("missing regmap for %pOFn\n", node);
+		return;
+	}
+
+	if (of_property_read_u32_index(node, "fsl,anatop", 1, &val)) {
+		pr_err("missing register offset for %pOFn\n", node);
+		return;
+	}
+
+	reg.offset = val;
+
+	if (!of_property_read_u32(node, "fsl,bit-shift", &val))
+		enable_bit = val;
+
+	if (of_clk_get_parent_count(node) != 1) {
+		pr_err("%pOFn must have 1 parent clock\n", node);
+		return;
+	}
+
+	of_property_read_string(node, "clock-output-names", &name);
+
+	hw = imx_clk_hw_register_gate(node, name, 0, &reg, enable_bit);
+	if (IS_ERR(hw))
+		return;
+
+	if (of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw)) {
+		imx_clk_hw_unregister_gate(hw);
+		return;
+	}
+
+	pr_debug("name: %s, offset: 0x%x, enable-bit: %d\n", name, reg.offset,
+		 enable_bit);
+}
+CLK_OF_DECLARE(fsl_imx8mn_gate_clk, "fsl,imx8mn-gate-clock",
+	       of_imx_gate_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 04/11] clk: imx8mn: add mux driver
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (2 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 03/11] clk: imx8mn: add gate driver Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 05/11] clk: imx8mn: add divider driver Dario Binacchi
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch adds support for imx8mn mux clocks to be initialized directly
from the device tree. Currently all i.MX mux clocks are initialized by
legacy code with hardwired parameters. This approach has generated setup
functions with unclear names:

git grep "#define imx_clk_hw_mux" drivers/clk/imx/clk.h
drivers/clk/imx/clk.h:#define imx_clk_hw_mux2(name, reg, shift, width, parents, num_parents) \
drivers/clk/imx/clk.h:#define imx_clk_hw_mux(name, reg, shift, width, parents, num_parents) \
drivers/clk/imx/clk.h:#define imx_clk_hw_mux_flags(name, reg, shift, width, parents, num_parents, flags) \
drivers/clk/imx/clk.h:#define imx_clk_hw_mux_ldb(name, reg, shift, width, parents, num_parents) \
drivers/clk/imx/clk.h:#define imx_clk_hw_mux2_flags(name, reg, shift, width, parents, num_parents, flags) \

So, let's start with this specific clock driver and hope that other
variants can be handled in the future, causing the legacy code to be
removed.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/Makefile  |   1 +
 drivers/clk/imx/clk-mux.c | 258 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 259 insertions(+)
 create mode 100644 drivers/clk/imx/clk-mux.c

diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 72e1f08d49dc..1cffc5bebbe1 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -15,6 +15,7 @@ mxc-clk-objs += clk-gate.o
 mxc-clk-objs += clk-gate2.o
 mxc-clk-objs += clk-gate-93.o
 mxc-clk-objs += clk-gate-exclusive.o
+mxc-clk-objs += clk-mux.o
 mxc-clk-objs += clk-pfd.o
 mxc-clk-objs += clk-pfdv2.o
 mxc-clk-objs += clk-pllv1.o
diff --git a/drivers/clk/imx/clk-mux.c b/drivers/clk/imx/clk-mux.c
new file mode 100644
index 000000000000..426738d25582
--- /dev/null
+++ b/drivers/clk/imx/clk-mux.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Amarula Solutions
+ *
+ * Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include "clk.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define to_clk_imx_mux(_hw) container_of(_hw, struct clk_imx_mux, hw)
+
+struct clk_imx_mux {
+	struct clk_hw hw;
+	struct imx_clk_reg reg;
+	u32 mask;
+	u8 shift;
+	u8 saved_parent;
+};
+
+static int imx_clk_mux_write(const struct imx_clk_reg *reg, u32 val)
+{
+	int ret = 0;
+
+	if (reg->base) {
+		writel(val, reg->base + reg->offset);
+	} else if (reg->regmap) {
+		ret = regmap_write(reg->regmap, reg->offset, val);
+	} else {
+		pr_err("memory address not set\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int imx_clk_mux_read(const struct imx_clk_reg *reg, u32 *val)
+{
+	int ret = 0;
+
+	if (reg->base) {
+		*val = readl(reg->base + reg->offset);
+	} else if (reg->regmap) {
+		ret = regmap_read(reg->regmap, reg->offset, val);
+	} else {
+		pr_err("memory address not set\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static u8 imx_clk_mux_get_parent(struct clk_hw *hw)
+{
+
+	struct clk_imx_mux *mux = to_clk_imx_mux(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+	unsigned int val;
+	int ret;
+
+	ret = imx_clk_mux_read(&mux->reg, &val);
+	if (ret)
+		return ret;
+
+	val = (val >> mux->shift) && mux->mask;
+
+	if (val >= num_parents)
+		return -EINVAL;
+
+	return val;
+}
+
+static int imx_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_imx_mux *mux = to_clk_imx_mux(hw);
+	unsigned int val;
+	int ret;
+
+	ret = imx_clk_mux_read(&mux->reg, &val);
+	if (ret)
+		return ret;
+
+	val &= ~(mux->mask << mux->shift);
+	val |= index << mux->shift;
+	return imx_clk_mux_write(&mux->reg, val);
+}
+
+/**
+ * imx_clk_mux_save_context - Save the parent selcted in the mux
+ * @hw: pointer  struct clk_hw
+ *
+ * Save the parent mux value.
+ */
+static int imx_clk_mux_save_context(struct clk_hw *hw)
+{
+	struct clk_imx_mux *mux = to_clk_imx_mux(hw);
+
+	mux->saved_parent = imx_clk_mux_get_parent(hw);
+	return 0;
+}
+
+/**
+ * imx_clk_mux_restore_context - Restore the parent in the mux
+ * @hw: pointer  struct clk_hw
+ *
+ * Restore the saved parent mux value.
+ */
+static void imx_clk_mux_restore_context(struct clk_hw *hw)
+{
+	struct clk_imx_mux *mux = to_clk_imx_mux(hw);
+
+	imx_clk_mux_set_parent(hw, mux->saved_parent);
+}
+
+const struct clk_ops imx_clk_mux_ops = {
+	.get_parent = imx_clk_mux_get_parent,
+	.set_parent = imx_clk_mux_set_parent,
+	.determine_rate = __clk_mux_determine_rate,
+	.save_context = imx_clk_mux_save_context,
+	.restore_context = imx_clk_mux_restore_context,
+};
+
+static void imx_clk_hw_unregister_mux(struct clk_hw *hw)
+{
+	struct clk_imx_mux *mux = to_clk_imx_mux(hw);
+
+	clk_hw_unregister(hw);
+	kfree(mux);
+}
+
+static struct clk_hw *imx_clk_hw_register_mux(struct device_node *node,
+					      const char *name,
+					      const char * const *parent_names,
+					      u8 num_parents,
+					      unsigned long flags,
+					      struct imx_clk_reg *reg, u8 shift,
+					      u32 mask)
+{
+	struct clk_init_data init = { NULL };
+	struct clk_imx_mux *mux;
+	struct clk_hw *hw;
+
+	int ret;
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = flags;
+	init.ops = &imx_clk_mux_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+
+	/* struct clk_mux assignments */
+	memcpy(&mux->reg, reg, sizeof(*reg));
+	mux->hw.init = &init;
+
+	hw = &mux->hw;
+	ret = of_clk_hw_register(node, hw);
+	if (ret) {
+		kfree(mux);
+		return ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+/**
+ * of_imx_mux_clk_setup() - Setup function for imx mux clock
+ * @node:	device node for the clock
+ */
+static void __init of_imx_mux_clk_setup(struct device_node *node)
+{
+	struct clk_hw *hw;
+	unsigned int num_parents;
+	const char **parent_names;
+	const char *name = node->name;
+	struct imx_clk_reg reg = {};
+	u32 shift = 0;
+	u32 flags = CLK_SET_RATE_NO_REPARENT;
+	u32 val;
+	u32 mask;
+
+	reg.regmap = syscon_regmap_lookup_by_phandle(node, "fsl,anatop");
+	if (!IS_ERR(reg.regmap)) {
+		if (of_property_read_u32_index(node, "fsl,anatop", 1, &val)) {
+			pr_err("missing register offset for %pOFn\n", node);
+			return;
+		}
+
+		reg.offset = val;
+	} else {
+		reg.base = of_iomap(node, 0);
+		if (IS_ERR(reg.base)) {
+			pr_err("failed to get register address for %pOFn\n",
+			       node);
+			return;
+		}
+	}
+
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents < 2) {
+		pr_err("%pOFn must have parents\n", node);
+		return;
+	}
+
+	parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
+	if (!parent_names)
+		return;
+
+	of_clk_parent_fill(node, parent_names, num_parents);
+
+	of_property_read_u32(node, "fsl,bit-shift", &shift);
+
+	if (of_property_read_bool(node, "fsl,is-critical"))
+		flags |= CLK_IS_CRITICAL;
+
+	if (of_property_read_bool(node, "fsl,ops-parent-enable"))
+		flags |= CLK_OPS_PARENT_ENABLE;
+
+	if (of_property_read_bool(node, "fsl,set-rate-parent"))
+		flags |= CLK_SET_RATE_PARENT;
+
+	/* Generate bit-mask based on parent info */
+	mask = num_parents - 1;
+	mask = (1 << fls(mask)) - 1;
+
+	of_property_read_string(node, "clock-output-names", &name);
+
+	hw = imx_clk_hw_register_mux(node, name, parent_names, num_parents,
+				     flags, &reg, shift, mask);
+	if (IS_ERR(hw))
+		goto free_parent_names;
+
+	if (of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw)) {
+		imx_clk_hw_unregister_mux(hw);
+		goto free_parent_names;
+	}
+
+	pr_debug("name: %s, offset: 0x%x, shift: %d, mask: 0x%x\n", name,
+		 reg.offset, shift, mask);
+
+free_parent_names:
+	kfree(parent_names);
+}
+CLK_OF_DECLARE(fsl_imx8mn_mux_clk, "fsl,imx8mn-mux-clock",
+	       of_imx_mux_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 05/11] clk: imx8mn: add divider driver
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (3 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 04/11] clk: imx8mn: add mux driver Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 06/11] clk: imx: pll14xx: add device tree support Dario Binacchi
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch adds support for imx8mn divider clocks to be initialized
directly from the device tree. Currently all i.MX divider clocks are
initialized by legacy code with hardwired parameters.

So, let's start with this specific clock driver and hope that other
variants can be handled in the future, causing the legacy code to be
removed.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/Makefile      |   1 +
 drivers/clk/imx/clk-divider.c | 235 ++++++++++++++++++++++++++++++++++
 2 files changed, 236 insertions(+)
 create mode 100644 drivers/clk/imx/clk-divider.c

diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 1cffc5bebbe1..0e4337f0a020 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -7,6 +7,7 @@ mxc-clk-objs += clk-composite-8m.o
 mxc-clk-objs += clk-composite-93.o
 mxc-clk-objs += clk-fracn-gppll.o
 mxc-clk-objs += clk-cpu.o
+mxc-clk-objs += clk-divider.o
 mxc-clk-objs += clk-divider-gate.o
 mxc-clk-objs += clk-fixup-div.o
 mxc-clk-objs += clk-fixup-mux.o
diff --git a/drivers/clk/imx/clk-divider.c b/drivers/clk/imx/clk-divider.c
new file mode 100644
index 000000000000..4617aa906de4
--- /dev/null
+++ b/drivers/clk/imx/clk-divider.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Amarula Solutions
+ *
+ * Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include "clk.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define to_clk_imx_divider(_hw) container_of(_hw, struct clk_imx_divider, hw)
+
+struct clk_imx_divider {
+	struct clk_hw hw;
+	struct imx_clk_reg reg;
+	u8 shift;
+	u8 width;
+};
+
+static int imx_clk_divider_write(const struct imx_clk_reg *reg, u32 val)
+{
+	int ret = 0;
+
+	if (reg->base) {
+		writel(val, reg->base + reg->offset);
+	} else if (reg->regmap) {
+		ret = regmap_write(reg->regmap, reg->offset, val);
+	} else {
+		pr_err("memory address not set\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int imx_clk_divider_read(const struct imx_clk_reg *reg, u32 *val)
+{
+	int ret = 0;
+
+	if (reg->base) {
+		*val = readl(reg->base + reg->offset);
+	} else if (reg->regmap) {
+		ret = regmap_read(reg->regmap, reg->offset, val);
+	} else {
+		pr_err("memory address not set\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static unsigned long imx_clk_divider_recalc_rate(struct clk_hw *hw,
+						 unsigned long parent_rate)
+{
+	struct clk_imx_divider *divider = to_clk_imx_divider(hw);
+	unsigned int val;
+	int ret;
+
+	ret = imx_clk_divider_read(&divider->reg, &val);
+	if (ret)
+		return 0;
+
+	val >>= divider->shift;
+	val &= clk_div_mask(divider->width);
+
+	return divider_recalc_rate(hw, parent_rate, val, NULL, 0,
+				   divider->width);
+}
+
+static long imx_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long *prate)
+{
+	struct clk_imx_divider *divider = to_clk_imx_divider(hw);
+
+	return divider_round_rate(hw, rate, prate, NULL, divider->width, 0);
+}
+
+static int imx_clk_divider_determine_rate(struct clk_hw *hw,
+					  struct clk_rate_request *req)
+{
+	struct clk_imx_divider *divider = to_clk_imx_divider(hw);
+
+	return divider_determine_rate(hw, req, NULL, divider->width, 0);
+}
+
+static int imx_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long parent_rate)
+{
+	struct clk_imx_divider *divider = to_clk_imx_divider(hw);
+	unsigned int val;
+	int div, ret;
+
+	div = divider_get_val(rate, parent_rate, NULL, divider->width, 0);
+	if (div < 0)
+		return div;
+
+	ret = imx_clk_divider_read(&divider->reg, &val);
+	if (ret)
+		return ret;
+
+	val &= ~(clk_div_mask(divider->width) << divider->shift);
+	val |= div << divider->shift;
+	return imx_clk_divider_write(&divider->reg, val);
+}
+
+const struct clk_ops imx_clk_divider_ops = {
+	.recalc_rate = imx_clk_divider_recalc_rate,
+	.round_rate = imx_clk_divider_round_rate,
+	.determine_rate = imx_clk_divider_determine_rate,
+	.set_rate = imx_clk_divider_set_rate,
+};
+
+static void imx_clk_hw_unregister_divider(struct clk_hw *hw)
+{
+	struct clk_imx_divider *divider = to_clk_imx_divider(hw);
+
+	clk_hw_unregister(hw);
+	kfree(divider);
+}
+
+static struct clk_hw *imx_clk_hw_register_divider(struct device_node *node,
+						  const char *name,
+						  unsigned long flags,
+						  struct imx_clk_reg *reg,
+						  u8 shift, u8 width)
+{
+	struct clk_parent_data pdata = { .index = 0 };
+	struct clk_init_data init = { NULL };
+	struct clk_imx_divider *divider;
+	struct clk_hw *hw;
+	int ret;
+
+	divider = kzalloc(sizeof(*divider), GFP_KERNEL);
+	if (!divider)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = flags;
+	init.ops = &imx_clk_divider_ops;
+	init.parent_data = &pdata;
+	init.num_parents = 1;
+
+	memcpy(&divider->reg, reg, sizeof(*reg));
+	divider->shift = shift;
+	divider->width = width;
+	divider->hw.init = &init;
+
+	hw = &divider->hw;
+	ret = of_clk_hw_register(node, hw);
+	if (ret) {
+		kfree(divider);
+		return ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+/**
+ * of_imx_divider_clk_setup() - Setup function for imx gate clock
+ * @node:	device node for the clock
+ */
+static void __init of_imx_divider_clk_setup(struct device_node *node)
+{
+	struct clk_hw *hw;
+	struct imx_clk_reg reg = {};
+	const char *name = node->name;
+	u8 shift = 0;
+	u8 width;
+	u32 flags = 0;
+	u32 val;
+
+	reg.regmap = syscon_regmap_lookup_by_phandle(node, "fsl,anatop");
+	if (!IS_ERR(reg.regmap)) {
+		if (of_property_read_u32_index(node, "fsl,anatop", 1, &val)) {
+			pr_err("missing register offset for %pOFn\n", node);
+			return;
+		}
+
+		reg.offset = val;
+	} else {
+		reg.base = of_iomap(node, 0);
+		if (IS_ERR(reg.base)) {
+			pr_err("failed to get register address for %pOFn\n",
+			       node);
+			return;
+		}
+	}
+
+	if (!of_property_read_u32(node, "fsl,bit-shift", &val))
+		shift = val;
+
+	if (of_property_read_u32(node, "fsl,width", &val)) {
+		pr_err("missing width for %pOFn\n", node);
+		return;
+
+	}
+
+	width = val;
+
+	if (of_property_read_bool(node, "fsl,ops-parent-enable"))
+		flags |= CLK_OPS_PARENT_ENABLE;
+
+	if (of_property_read_bool(node, "fsl,set-rate-parent"))
+		flags |= CLK_SET_RATE_PARENT;
+
+	if (of_clk_get_parent_count(node) != 1) {
+		pr_err("%pOFn must have 1 parent clock\n", node);
+		return;
+	}
+
+	of_property_read_string(node, "clock-output-names", &name);
+
+	hw = imx_clk_hw_register_divider(node, name, flags, &reg, shift, width);
+	if (IS_ERR(hw))
+		return;
+
+	if (of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw)) {
+		imx_clk_hw_unregister_divider(hw);
+		return;
+	}
+
+	pr_debug("name: %s, offset: 0x%x, shift: %d, width: %d\n", name,
+		 reg.offset, shift, width);
+}
+CLK_OF_DECLARE(fsl_imx8mn_divider_clk, "fsl,imx8mn-divider-clock",
+	       of_imx_divider_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 06/11] clk: imx: pll14xx: add device tree support
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (4 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 05/11] clk: imx8mn: add divider driver Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 07/11] clk: imx: composite-8m: " Dario Binacchi
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch, backwards compatible, extends the driver to initialize the
clock directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk-pll14xx.c | 220 +++++++++++++++++++++++++++-------
 1 file changed, 176 insertions(+), 44 deletions(-)

diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index 828336873a98..6503005b885a 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -12,6 +12,10 @@
 #include <linux/export.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 
@@ -36,7 +40,9 @@
 
 struct clk_pll14xx {
 	struct clk_hw			hw;
-	void __iomem			*base;
+	struct imx_clk_reg		gnrl_ctl;
+	struct imx_clk_reg		div_ctl0;
+	struct imx_clk_reg		div_ctl1;
 	enum imx_pll14xx_type		type;
 	const struct imx_pll14xx_rate_table *rate_table;
 	int rate_count;
@@ -90,6 +96,30 @@ struct imx_pll14xx_clk imx_1416x_pll = {
 };
 EXPORT_SYMBOL_GPL(imx_1416x_pll);
 
+static void imx_pll14xx_writel(u32 val, const struct imx_clk_reg *reg)
+{
+	if (reg->base)
+		writel_relaxed(val, reg->base + reg->offset);
+	else if (reg->regmap)
+		regmap_write(reg->regmap, reg->offset, val);
+	else
+		pr_err("%s: memory address not set\n", __func__);
+}
+
+static u32 imx_pll14xx_readl(const struct imx_clk_reg *reg)
+{
+	u32 val = 0;
+
+	if (reg->base)
+		val = readl_relaxed(reg->base + reg->offset);
+	else if (reg->regmap)
+		regmap_read(reg->regmap, reg->offset, &val);
+	else
+		pr_err("%s: memory address not set\n", __func__);
+
+	return val;
+}
+
 static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
 		struct clk_pll14xx *pll, unsigned long rate)
 {
@@ -161,11 +191,11 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
 		return;
 	}
 
-	pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
+	pll_div_ctl0 = imx_pll14xx_readl(&pll->div_ctl0);
 	mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
 	pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
 	sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
-	pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
+	pll_div_ctl1 = imx_pll14xx_readl(&pll->div_ctl1);
 
 	/* Then see if we can get the desired rate by only adjusting kdiv (glitch free) */
 	rate_min = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, KDIV_MIN, prate);
@@ -249,13 +279,13 @@ static unsigned long clk_pll14xx_recalc_rate(struct clk_hw *hw,
 	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
 	u32 mdiv, pdiv, sdiv, kdiv, pll_div_ctl0, pll_div_ctl1;
 
-	pll_div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
+	pll_div_ctl0 = imx_pll14xx_readl(&pll->div_ctl0);
 	mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
 	pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
 	sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
 
 	if (pll->type == PLL_1443X) {
-		pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
+		pll_div_ctl1 = imx_pll14xx_readl(&pll->div_ctl1);
 		kdiv = FIELD_GET(KDIV_MASK, pll_div_ctl1);
 	} else {
 		kdiv = 0;
@@ -277,10 +307,22 @@ static inline bool clk_pll14xx_mp_change(const struct imx_pll14xx_rate_table *ra
 
 static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
 {
+	struct imx_clk_reg *reg = &pll->gnrl_ctl;
 	u32 val;
 
-	return readl_poll_timeout(pll->base + GNRL_CTL, val, val & LOCK_STATUS, 0,
-			LOCK_TIMEOUT_US);
+	if (reg->base)
+		return readl_poll_timeout(reg->base + reg->offset, val,
+					  val & LOCK_STATUS, 0,
+					  LOCK_TIMEOUT_US);
+
+	if (reg->regmap)
+		return regmap_read_poll_timeout(reg->regmap, reg->offset, val,
+						val & LOCK_STATUS, 0,
+						LOCK_TIMEOUT_US);
+
+	pr_err("%s: memory address not set\n", __func__);
+
+	return -EIO;
 }
 
 static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
@@ -298,32 +340,32 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 		return -EINVAL;
 	}
 
-	tmp = readl_relaxed(pll->base + DIV_CTL0);
+	tmp = imx_pll14xx_readl(&pll->div_ctl0);
 
 	if (!clk_pll14xx_mp_change(rate, tmp)) {
 		tmp &= ~SDIV_MASK;
 		tmp |= FIELD_PREP(SDIV_MASK, rate->sdiv);
-		writel_relaxed(tmp, pll->base + DIV_CTL0);
+		imx_pll14xx_writel(tmp, &pll->div_ctl0);
 
 		return 0;
 	}
 
 	/* Bypass clock and set lock to pll output lock */
-	tmp = readl_relaxed(pll->base + GNRL_CTL);
+	tmp = imx_pll14xx_readl(&pll->gnrl_ctl);
 	tmp |= LOCK_SEL_MASK;
-	writel_relaxed(tmp, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(tmp, &pll->gnrl_ctl);
 
 	/* Enable RST */
 	tmp &= ~RST_MASK;
-	writel_relaxed(tmp, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(tmp, &pll->gnrl_ctl);
 
 	/* Enable BYPASS */
 	tmp |= BYPASS_MASK;
-	writel(tmp, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(tmp, &pll->gnrl_ctl);
 
 	div_val = FIELD_PREP(MDIV_MASK, rate->mdiv) | FIELD_PREP(PDIV_MASK, rate->pdiv) |
 		FIELD_PREP(SDIV_MASK, rate->sdiv);
-	writel_relaxed(div_val, pll->base + DIV_CTL0);
+	imx_pll14xx_writel(div_val, &pll->div_ctl0);
 
 	/*
 	 * According to SPEC, t3 - t2 need to be greater than
@@ -335,7 +377,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 
 	/* Disable RST */
 	tmp |= RST_MASK;
-	writel_relaxed(tmp, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(tmp, &pll->gnrl_ctl);
 
 	/* Wait Lock */
 	ret = clk_pll14xx_wait_lock(pll);
@@ -344,7 +386,7 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 
 	/* Bypass */
 	tmp &= ~BYPASS_MASK;
-	writel_relaxed(tmp, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(tmp, &pll->gnrl_ctl);
 
 	return 0;
 }
@@ -359,35 +401,35 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 
 	imx_pll14xx_calc_settings(pll, drate, prate, &rate);
 
-	div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
+	div_ctl0 = imx_pll14xx_readl(&pll->div_ctl0);
 
 	if (!clk_pll14xx_mp_change(&rate, div_ctl0)) {
 		/* only sdiv and/or kdiv changed - no need to RESET PLL */
 		div_ctl0 &= ~SDIV_MASK;
 		div_ctl0 |= FIELD_PREP(SDIV_MASK, rate.sdiv);
-		writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
+		imx_pll14xx_writel(div_ctl0, &pll->div_ctl0);
 
-		writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv),
-			       pll->base + DIV_CTL1);
+		imx_pll14xx_writel(FIELD_PREP(KDIV_MASK, rate.kdiv),
+				   &pll->div_ctl1);
 
 		return 0;
 	}
 
 	/* Enable RST */
-	gnrl_ctl = readl_relaxed(pll->base + GNRL_CTL);
+	gnrl_ctl = imx_pll14xx_readl(&pll->gnrl_ctl);
 	gnrl_ctl &= ~RST_MASK;
-	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl);
 
 	/* Enable BYPASS */
 	gnrl_ctl |= BYPASS_MASK;
-	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl);
 
 	div_ctl0 = FIELD_PREP(MDIV_MASK, rate.mdiv) |
 		   FIELD_PREP(PDIV_MASK, rate.pdiv) |
 		   FIELD_PREP(SDIV_MASK, rate.sdiv);
-	writel_relaxed(div_ctl0, pll->base + DIV_CTL0);
+	imx_pll14xx_writel(div_ctl0, &pll->div_ctl0);
 
-	writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1);
+	imx_pll14xx_writel(FIELD_PREP(KDIV_MASK, rate.kdiv), &pll->div_ctl1);
 
 	/*
 	 * According to SPEC, t3 - t2 need to be greater than
@@ -399,7 +441,7 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 
 	/* Disable RST */
 	gnrl_ctl |= RST_MASK;
-	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl);
 
 	/* Wait Lock*/
 	ret = clk_pll14xx_wait_lock(pll);
@@ -408,7 +450,7 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 
 	/* Bypass */
 	gnrl_ctl &= ~BYPASS_MASK;
-	writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(gnrl_ctl, &pll->gnrl_ctl);
 
 	return 0;
 }
@@ -423,20 +465,20 @@ static int clk_pll14xx_prepare(struct clk_hw *hw)
 	 * RESETB = 1 from 0, PLL starts its normal
 	 * operation after lock time
 	 */
-	val = readl_relaxed(pll->base + GNRL_CTL);
+	val = imx_pll14xx_readl(&pll->gnrl_ctl);
 	if (val & RST_MASK)
 		return 0;
 	val |= BYPASS_MASK;
-	writel_relaxed(val, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(val, &pll->gnrl_ctl);
 	val |= RST_MASK;
-	writel_relaxed(val, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(val, &pll->gnrl_ctl);
 
 	ret = clk_pll14xx_wait_lock(pll);
 	if (ret)
 		return ret;
 
 	val &= ~BYPASS_MASK;
-	writel_relaxed(val, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(val, &pll->gnrl_ctl);
 
 	return 0;
 }
@@ -446,7 +488,7 @@ static int clk_pll14xx_is_prepared(struct clk_hw *hw)
 	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
 	u32 val;
 
-	val = readl_relaxed(pll->base + GNRL_CTL);
+	val = imx_pll14xx_readl(&pll->gnrl_ctl);
 
 	return (val & RST_MASK) ? 1 : 0;
 }
@@ -460,9 +502,9 @@ static void clk_pll14xx_unprepare(struct clk_hw *hw)
 	 * Set RST to 0, power down mode is enabled and
 	 * every digital block is reset
 	 */
-	val = readl_relaxed(pll->base + GNRL_CTL);
+	val = imx_pll14xx_readl(&pll->gnrl_ctl);
 	val &= ~RST_MASK;
-	writel_relaxed(val, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(val, &pll->gnrl_ctl);
 }
 
 static const struct clk_ops clk_pll1416x_ops = {
@@ -487,13 +529,24 @@ static const struct clk_ops clk_pll1443x_ops = {
 	.set_rate	= clk_pll1443x_set_rate,
 };
 
-struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
-				const char *parent_name, void __iomem *base,
-				const struct imx_pll14xx_clk *pll_clk)
+static void imx_clk_hw_unregister_pll14xx(struct clk_hw *hw)
 {
+	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+
+	clk_hw_unregister(hw);
+	kfree(pll);
+}
+
+static struct clk_hw *
+imx_clk_hw_register_pll14xx(struct device_node *node, const char *name,
+			    const char *parent_name,
+			    struct imx_clk_reg *iomap,
+			    const struct imx_pll14xx_clk *pll_clk)
+{
+	struct clk_parent_data pdata = { .index = 0 };
+	struct clk_init_data init = { NULL };
 	struct clk_pll14xx *pll;
 	struct clk_hw *hw;
-	struct clk_init_data init;
 	int ret;
 	u32 val;
 
@@ -503,7 +556,8 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
 
 	init.name = name;
 	init.flags = pll_clk->flags;
-	init.parent_names = &parent_name;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.parent_data = &pdata;
 	init.num_parents = 1;
 
 	switch (pll_clk->type) {
@@ -522,19 +576,24 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
 		return ERR_PTR(-EINVAL);
 	}
 
-	pll->base = base;
+	memcpy(&pll->gnrl_ctl, iomap, sizeof(*iomap));
+	pll->gnrl_ctl.offset += GNRL_CTL;
+	memcpy(&pll->div_ctl0, iomap, sizeof(*iomap));
+	pll->div_ctl0.offset += DIV_CTL0;
+	memcpy(&pll->div_ctl1, iomap, sizeof(*iomap));
+	pll->div_ctl1.offset += DIV_CTL1;
+
 	pll->hw.init = &init;
 	pll->type = pll_clk->type;
 	pll->rate_table = pll_clk->rate_table;
 	pll->rate_count = pll_clk->rate_count;
 
-	val = readl_relaxed(pll->base + GNRL_CTL);
+	val = imx_pll14xx_readl(&pll->gnrl_ctl);
 	val &= ~BYPASS_MASK;
-	writel_relaxed(val, pll->base + GNRL_CTL);
+	imx_pll14xx_writel(val, &pll->gnrl_ctl);
 
 	hw = &pll->hw;
-
-	ret = clk_hw_register(dev, hw);
+	ret = of_clk_hw_register(node, hw);
 	if (ret) {
 		pr_err("failed to register pll %s %d\n", name, ret);
 		kfree(pll);
@@ -543,4 +602,77 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
 
 	return hw;
 }
+
+struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
+				const char *parent_name, void __iomem *base,
+				const struct imx_pll14xx_clk *pll_clk)
+{
+	struct imx_clk_reg iomap = {};
+
+	iomap.base = base;
+	return imx_clk_hw_register_pll14xx(dev_of_node(dev), name, parent_name,
+					   &iomap, pll_clk);
+}
 EXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx);
+
+/**
+ * of_imx_pll14xx_clk_setup() - Setup function for imx pll14xx clock
+ * @node:	device node for the clock
+ */
+static void __init of_imx_pll14xx_clk_setup(struct device_node *node)
+{
+	struct clk_hw *hw;
+	struct imx_clk_reg iomap = {};
+	const char *name = node->name;
+	const struct imx_pll14xx_clk *pll_clk;
+	const char *pll_type;
+	u32 val;
+
+	iomap.regmap = syscon_regmap_lookup_by_phandle(node, "fsl,anatop");
+	if (IS_ERR(iomap.regmap)) {
+		pr_err("missing regmap for %pOFn\n", node);
+		return;
+	}
+
+	if (of_property_read_u32_index(node, "fsl,anatop", 1, &val)) {
+		pr_err("missing register offset for %pOFn\n", node);
+		return;
+	}
+
+	iomap.offset = val;
+	if (of_clk_get_parent_count(node) != 1) {
+		pr_err("%pOFn must have 1 parent clock\n", node);
+		return;
+	}
+
+	of_property_read_string(node, "clock-output-names", &name);
+	if (of_property_read_string(node, "fsl,type", &pll_type)) {
+		pr_err("missing 'fsl,type' for %pOFn\n", node);
+		return;
+	}
+
+	if (!strcmp(pll_type, "1443x")) {
+		if (of_property_read_bool(node, "fsl,get-rate-nocache"))
+			pll_clk = &imx_1443x_dram_pll;
+		else
+			pll_clk = &imx_1443x_pll;
+	} else if (!strcmp(pll_type, "1416x")) {
+		pll_clk = &imx_1416x_pll;
+	} else {
+		pr_err("failed to get pll clock for %pOFn\n", node);
+		return;
+	}
+
+	hw = imx_clk_hw_register_pll14xx(node, name, NULL, &iomap, pll_clk);
+	if (IS_ERR(hw))
+		return;
+
+	if (of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw)) {
+		imx_clk_hw_unregister_pll14xx(hw);
+		return;
+	}
+
+	pr_debug("name: %s, offset: 0x%x, pll_type: %s\n", name, iomap.offset,
+		 pll_type);
+}
+CLK_OF_DECLARE(fsl_pll14xx_clk, "fsl,pll14xx-clock", of_imx_pll14xx_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 07/11] clk: imx: composite-8m: add device tree support
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (5 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 06/11] clk: imx: pll14xx: add device tree support Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 08/11] clk: imx: gate2: " Dario Binacchi
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch, backwards compatible, extends the driver to initialize the
clock directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk-composite-8m.c | 83 ++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
index cbf0d7955a00..8c945d180318 100644
--- a/drivers/clk/imx/clk-composite-8m.c
+++ b/drivers/clk/imx/clk-composite-8m.c
@@ -7,6 +7,8 @@
 #include <linux/errno.h>
 #include <linux/export.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/slab.h>
 
 #include "clk.h"
@@ -25,6 +27,9 @@
 
 #define PCG_CGC_SHIFT		28
 
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk_hw *hw,
 						unsigned long parent_rate)
 {
@@ -250,3 +255,81 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name,
 	return ERR_CAST(hw);
 }
 EXPORT_SYMBOL_GPL(__imx8m_clk_hw_composite);
+
+static void __init _of_imx_composite_clk_setup(struct device_node *node,
+					       u32 type)
+{
+	void __iomem *reg;
+	struct clk_hw *hw;
+	const char *name = node->name;
+	unsigned int num_parents;
+	const char **parent_names;
+	unsigned long flags = IMX_COMPOSITE_CLK_FLAGS_DEFAULT;
+
+	reg = of_iomap(node, 0);
+	if (IS_ERR(reg)) {
+		pr_err("failed to get reg address for %pOFn\n", node);
+		return;
+	}
+
+	num_parents = of_clk_get_parent_count(node);
+	if (num_parents < 2) {
+		pr_err("%pOFn must have parents\n", node);
+		return;
+	}
+
+	parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
+	if (!parent_names)
+		return;
+
+	of_clk_parent_fill(node, parent_names, num_parents);
+	of_property_read_string(node, "clock-output-names", &name);
+
+	if (of_property_read_bool(node, "fsl,get-rate-nocache"))
+		flags |= CLK_GET_RATE_NOCACHE;
+
+	if (of_property_read_bool(node, "fsl,is-critical"))
+		flags |= CLK_IS_CRITICAL;
+
+	hw = __imx8m_clk_hw_composite(name, parent_names, num_parents, reg,
+				      type, flags);
+	if (!IS_ERR(hw))
+		of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
+
+	kfree(parent_names);
+}
+
+/**
+ * of_imx_composite_clk_setup() - Setup function for imx composite  clock
+ * @node:	device node for the clock
+ */
+void __init of_imx_composite_clk_setup(struct device_node *node)
+{
+	_of_imx_composite_clk_setup(node, IMX_COMPOSITE_CORE);
+}
+CLK_OF_DECLARE(fsl_composite_8m_clk, "fsl,imx8m-composite-clock",
+	       of_imx_composite_clk_setup);
+
+/**
+ * of_imx_composite_bus_clk_setup() - Setup function for imx composite  clock
+ * @node:	device node for the clock
+ */
+void __init of_imx_composite_bus_clk_setup(struct device_node *node)
+{
+	_of_imx_composite_clk_setup(node, IMX_COMPOSITE_BUS);
+}
+CLK_OF_DECLARE(fsl_composite_bus_8m_clk, "fsl,imx8m-composite-bus-clock",
+	       of_imx_composite_bus_clk_setup);
+
+/**
+ * of_imx_composite_fw_managed_clk_setup() - Setup function for imx
+ *		composite fw managed clock
+ * @node:	device node for the clock
+ */
+void __init of_imx_composite_fw_managed_clk_setup(struct device_node *node)
+{
+	_of_imx_composite_clk_setup(node, IMX_COMPOSITE_FW_MANAGED);
+}
+CLK_OF_DECLARE(fsl_composite_fw_managed_8m_clk,
+	       "fsl,imx8m-composite-fw-managed-clock",
+	       of_imx_composite_fw_managed_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 08/11] clk: imx: gate2: add device tree support
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (6 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 07/11] clk: imx: composite-8m: " Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 09/11] clk: imx: cpu: " Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 10/11] arm64: dts: imx8mn: add dumy clock Dario Binacchi
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch, backwards compatible, extends the driver to initialize the
clock directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk-gate2.c | 86 +++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index f16c4019f402..b28150bf1ff6 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -12,9 +12,26 @@
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/string.h>
 #include "clk.h"
 
+#define CLK_GATE2_CGR_DISABLED 0
+#define CLK_GATE2_CGR_RUN 1
+#define CLK_GATE2_CGR_RUN_WAIT 2
+#define CLK_GATE2_CGR_RUN_WAIT_STOP 3
+#define CLK_GATE2_CGR_MASK 3
+
+#define CLK_GATE2_MAX_GROUPS    16
+
+struct clk_gate2_group {
+	const char *name;
+	unsigned int share_count;
+};
+
+static struct clk_gate2_group clk_gate2_groups[CLK_GATE2_MAX_GROUPS];
+
 /**
  * DOC: basic gateable clock which can gate and ungate its output
  *
@@ -175,3 +192,72 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name,
 	return hw;
 }
 EXPORT_SYMBOL_GPL(clk_hw_register_gate2);
+
+/**
+ * of_imx_gate2_clk_setup() - Setup function for imx low power gate
+ *                            clock
+ * @node:	device node for the clock
+ */
+static void __init of_imx_gate2_clk_setup(struct device_node *node)
+{
+	void __iomem *reg;
+	u8 i, bit_idx = 0;
+	u8 cgr_val = CLK_GATE2_CGR_RUN_WAIT_STOP;
+	u8 cgr_mask = CLK_GATE2_CGR_MASK;
+	unsigned long flags = CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT;
+	u8 gate2_flags = 0;
+	unsigned int *share_count = NULL;
+	const char *name = node->name, *parent_name;
+	const char *str;
+	struct clk_hw *hw;
+	u32 val;
+
+	reg = of_iomap(node, 0);
+	if (IS_ERR(reg)) {
+		pr_err("failed to get reg address for %pOFn\n", node);
+		return;
+	}
+
+	if (!of_property_read_u32(node, "fsl,bit-shift", &val))
+		bit_idx = val;
+
+	if (of_clk_get_parent_count(node) != 1) {
+		pr_err("%pOFn must have 1 parent clock\n", node);
+		return;
+	}
+
+	if (!of_property_read_string(node, "sharing-group", &str)) {
+		for (i = 0; clk_gate2_groups[i].name &&
+			     i < ARRAY_SIZE(clk_gate2_groups); i++) {
+			if (!strcmp(clk_gate2_groups[i].name, str)) {
+				share_count = &clk_gate2_groups[i].share_count;
+				break;
+			}
+		}
+
+		if (i == ARRAY_SIZE(clk_gate2_groups)) {
+			pr_err("failed to get shared count for %pOFn\n", node);
+			return;
+		}
+
+		if (!share_count) {
+			clk_gate2_groups[i].name =
+				kstrdup_const(str, GFP_KERNEL);
+			share_count = &clk_gate2_groups[i].share_count;
+		}
+	}
+
+	parent_name = of_clk_get_parent_name(node, 0);
+	of_property_read_string(node, "clock-output-names", &name);
+
+	hw = clk_hw_register_gate2(NULL, name, parent_name, flags, reg, bit_idx,
+				   cgr_val, cgr_mask, gate2_flags,
+				   &imx_ccm_lock, share_count);
+	if (!IS_ERR(hw))
+		of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
+
+	pr_debug("name: %s, parent: %s, enable-bit: %d, flags: 0x%lx, gate2_flags: 0x%x\n",
+		 name, parent_name, bit_idx, flags, gate2_flags);
+}
+CLK_OF_DECLARE(fsl_imx8mn_gate2_clk, "fsl,imx8mn-low-power-gate-clock",
+	       of_imx_gate2_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 09/11] clk: imx: cpu: add device tree support
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (7 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 08/11] clk: imx: gate2: " Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  2022-12-31 10:47 ` [RFC PATCH 10/11] arm64: dts: imx8mn: add dumy clock Dario Binacchi
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Fabio Estevam,
	Michael Turquette, NXP Linux Team, Pengutronix Kernel Team,
	Sascha Hauer, Shawn Guo, Stephen Boyd, linux-arm-kernel,
	linux-clk

The patch, backwards compatible, extends the driver to initialize the
clock directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk-cpu.c | 54 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c
index cb6ca4cf0535..28fb75c6ecea 100644
--- a/drivers/clk/imx/clk-cpu.c
+++ b/drivers/clk/imx/clk-cpu.c
@@ -106,3 +106,57 @@ struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name,
 	return hw;
 }
 EXPORT_SYMBOL_GPL(imx_clk_hw_cpu);
+
+/**
+ * of_imx_cpu_clk_setup - Setup function for imx low power gate
+ *                            clock
+ * @node:	device node for the clock
+ */
+static void __init of_imx_cpu_clk_setup(struct device_node *node)
+{
+	struct clk_hw *hw;
+	struct clk *parent_clk, *div, *mux, *pll, *step;
+	const char *name = node->name, *parent_name;
+
+	parent_clk = of_clk_get_by_name(node, "fck");
+	if (IS_ERR(parent_clk)) {
+		pr_err("failed to get parent clock for %pOFn\n", node);
+		return;
+	}
+
+	div = of_clk_get_by_name(node, "div-clk");
+	if (IS_ERR(div)) {
+		pr_err("failed to get div clock for %pOFn\n", node);
+		return;
+	}
+
+	mux = of_clk_get_by_name(node, "mux-clk");
+	if (IS_ERR(div)) {
+		pr_err("failed to get mux clock for %pOFn\n", node);
+		return;
+	}
+
+	pll = of_clk_get_by_name(node, "pll-clk");
+	if (IS_ERR(div)) {
+		pr_err("failed to get pll clock for %pOFn\n", node);
+		return;
+	}
+
+	step = of_clk_get_by_name(node, "step-clk");
+	if (IS_ERR(div)) {
+		pr_err("failed to get step clock for %pOFn\n", node);
+		return;
+	}
+
+	parent_name = __clk_get_name(parent_clk);
+	of_property_read_string(node, "clock-output-names", &name);
+
+	hw = imx_clk_hw_cpu(name, parent_name, div, mux, pll, step);
+	if (!IS_ERR(hw))
+		of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
+
+	pr_debug("name: %s, parent: %s, div: %s, mux: %s, pll: %s, step: %s\n",
+		 name, parent_name, __clk_get_name(div), __clk_get_name(mux),
+		 __clk_get_name(pll), __clk_get_name(step));
+}
+CLK_OF_DECLARE(fsl_cpu_clk, "fsl,cpu-clock", of_imx_cpu_clk_setup);
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH 10/11] arm64: dts: imx8mn: add dumy clock
  2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
                   ` (8 preceding siblings ...)
  2022-12-31 10:47 ` [RFC PATCH 09/11] clk: imx: cpu: " Dario Binacchi
@ 2022-12-31 10:47 ` Dario Binacchi
  9 siblings, 0 replies; 11+ messages in thread
From: Dario Binacchi @ 2022-12-31 10:47 UTC (permalink / raw)
  To: linux-kernel
  Cc: tommaso.merciai, linux-amarula, Chen-Yu Tsai, jagan, angelo,
	anthony, michael, Dario Binacchi, Abel Vesa, Adam Ford,
	Fabio Estevam, Krzysztof Kozlowski, Li Jun, Lucas Stach,
	Marek Vasut, Markus Niebel, Michael Turquette, NXP Linux Team,
	Pengutronix Kernel Team, Rob Herring, Sascha Hauer, Shawn Guo,
	Stephen Boyd, devicetree, linux-arm-kernel, linux-clk

The dummy clock was the only fixed rate clock not initialized from the
device tree. So let's add it to the device tree like we did for the
others fixed rate clocks.

This is a preparation patch for the upcoming support to setup all the
clocks directly from the device tree.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 arch/arm64/boot/dts/freescale/imx8mn.dtsi | 11 +++++++++--
 drivers/clk/imx/clk-imx8mn.c              |  2 +-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index b7d91df71cc2..1949db3e08f7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -217,6 +217,13 @@ clk_ext4: clock-ext4 {
 		clock-output-names = "clk_ext4";
 	};
 
+	clk_dummy: clock-dummy {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <0>;
+		clock-output-names = "dummy";
+	};
+
 	pmu {
 		compatible = "arm,cortex-a53-pmu";
 		interrupts = <GIC_PPI 7
@@ -614,9 +621,9 @@ clk: clock-controller@30380000 {
 				reg = <0x30380000 0x10000>;
 				#clock-cells = <1>;
 				clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
-					 <&clk_ext3>, <&clk_ext4>;
+					 <&clk_ext3>, <&clk_ext4>, <&clk_dummy>;
 				clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
-					      "clk_ext3", "clk_ext4";
+					      "clk_ext3", "clk_ext4", "dummy";
 				assigned-clocks = <&clk IMX8MN_CLK_A53_SRC>,
 						<&clk IMX8MN_CLK_A53_CORE>,
 						<&clk IMX8MN_CLK_NOC>,
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index af256ade554f..e1f059dc5afa 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -331,7 +331,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
 	clk_hw_data->num = IMX8MN_CLK_END;
 	hws = clk_hw_data->hws;
 
-	hws[IMX8MN_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
+	hws[IMX8MN_CLK_DUMMY] = imx_get_clk_hw_by_name(np, "dummy");
 	hws[IMX8MN_CLK_24M] = imx_get_clk_hw_by_name(np, "osc_24m");
 	hws[IMX8MN_CLK_32K] = imx_get_clk_hw_by_name(np, "osc_32k");
 	hws[IMX8MN_CLK_EXT1] = imx_get_clk_hw_by_name(np, "clk_ext1");
-- 
2.32.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2022-12-31 10:57 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-31 10:47 [RFC PATCH 00/11] clk: imx8mn: setup clocks from the device tree Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 01/11] clk: imx: add structure to extend register accesses Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 02/11] clk: imx: add clk_hw based API imx_get_clk_hw_from_dt() Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 03/11] clk: imx8mn: add gate driver Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 04/11] clk: imx8mn: add mux driver Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 05/11] clk: imx8mn: add divider driver Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 06/11] clk: imx: pll14xx: add device tree support Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 07/11] clk: imx: composite-8m: " Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 08/11] clk: imx: gate2: " Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 09/11] clk: imx: cpu: " Dario Binacchi
2022-12-31 10:47 ` [RFC PATCH 10/11] arm64: dts: imx8mn: add dumy clock Dario Binacchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).