Skip to contentSkip to conversation

clk: exynos4: migrate to common clock framework

PATCH Superseded Thomas Abraham 7 participants 18 messages Oct 7, 2012 – Nov 14, 2012

Subsystems (6)

v2 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v2 cover clk: exynos4: migrate to common clock framework

This patch series removes the usage of Samsung specific clock for Exynos4 based platforms and migrates to use the common clock framework to register the clocks. Both legacy and device tree enabled Exynos4 platforms are supported. For legacy platforms, the clock instances are statically listed. For device tree based platforms, the device tree is searched for clock nodes and all available clock nodes are registered.

Thomas Abraham (5):
clk: samsung: add common clock framework support for Samsung platforms
clk: exynos4: register clocks using common clock framework
ARM: dts: Add Exynos4210 clock nodes
ARM: dts: list the clock providers for serial ports
ARM: Exynos4: Migrate clock support to common clock framework

 arch/arm/boot/dts/exynos4-clock.dtsi       |  389 +++++++++++++++++
 arch/arm/boot/dts/exynos4.dtsi             |    9 +
 arch/arm/mach-exynos/Kconfig               |    1 +
 arch/arm/mach-exynos/Makefile              |    3 -
 arch/arm/mach-exynos/clock-exynos4.h       |   35 --
 arch/arm/mach-exynos/clock-exynos4210.c    |  188 --------
 arch/arm/mach-exynos/clock-exynos4212.c    |  192 --------
 arch/arm/mach-exynos/common.c              |   22 +-
 arch/arm/mach-exynos/common.h              |    3 +
 arch/arm/mach-exynos/mach-armlex4210.c     |    1 -
 arch/arm/mach-exynos/mach-exynos4-dt.c     |    1 -
 arch/arm/mach-exynos/mach-nuri.c           |    1 -
 arch/arm/mach-exynos/mach-origen.c         |    1 -
 arch/arm/mach-exynos/mach-smdk4x12.c       |    1 -
 arch/arm/mach-exynos/mach-smdkv310.c       |    1 -
 arch/arm/mach-exynos/mach-universal_c210.c |    1 -
 arch/arm/mach-exynos/mct.c                 |   11 +-
 arch/arm/plat-samsung/Kconfig              |    4 +-
 drivers/clk/Makefile                       |    1 +
 drivers/clk/samsung/Makefile               |    6 +
 drivers/clk/samsung/clk-exynos4.c          |  647 ++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.c                  |  414 ++++++++++++++++++
 drivers/clk/samsung/clk.h                  |  212 +++++++++
 23 files changed, 1696 insertions(+), 448 deletions(-)
 create mode 100644 arch/arm/boot/dts/exynos4-clock.dtsi
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4.h
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4210.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4212.c
 create mode 100644 drivers/clk/samsung/Makefile
 create mode 100644 drivers/clk/samsung/clk-exynos4.c
 create mode 100644 drivers/clk/samsung/clk.c
 create mode 100644 drivers/clk/samsung/clk.h
Signature · 1 line
1.7.5.4
#1 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

All Samsung platforms include several types of clocks including fixed-rate, mux, divider and gate clock types. There are typically hundreds of such clocks on each of the Samsung platforms. To enable Samsung platforms to register these clocks using the common clock framework, a bunch of utility functions are introduced here which simplify the clock registration process.

In addition to the basic types of clock supported by common clock framework, a Samsung specific representation of the PLL clocks is also introduced.

Both legacy and device tree based Samsung platforms are supported. On legacy platforms, the clocks are statically instantiated and registered with common clock framework. On device tree enabled platforms, the device tree is searched and all clock nodes found are registered. It is also possible to register statically instantiated clocks on device tree enabled platforms.

Cc Mike Turquette <[email protected]>
Cc Kukjin Kim <[email protected]>
---
 drivers/clk/Makefile         |    1 +
 drivers/clk/samsung/Makefile |    5 +
 drivers/clk/samsung/clk.c    |  414 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h    |  212 +++++++++++++++++++++
 4 files changed, 632 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/Makefile
 create mode 100644 drivers/clk/samsung/clk.c
 create mode 100644 drivers/clk/samsung/clk.h
drivers/clk/Makefile +1 -0
index 71a25b9..95644e3 100644
@@ -19,6 +19,7 @@ endif
 obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
+obj-$(CONFIG_PLAT_SAMSUNG)	+= samsung/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
drivers/clk/samsung/Makefile new file +5 -0
new file mode 100644
index 0000000..3f926b0
@@ -0,0 +1,5 @@
+#
+# Samsung Clock specific Makefile
+#
+
+obj-$(CONFIG_PLAT_SAMSUNG)	+= clk.o
drivers/clk/samsung/clk.c new file +414 -0

414 lines not on this page · raw message

drivers/clk/samsung/clk.h new file +212 -0

212 lines not on this page · raw message

Signature · 1 line
1.7.5.4
#2 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

Hi Thomas,

Quoted 15 lines · Thomas Abraham

All Samsung platforms include several types of clocks including fixed-rate, mux, divider and gate clock types. There are typically hundreds of such clocks on each of the Samsung platforms. To enable Samsung platforms to register these clocks using the common clock framework, a bunch of utility functions are introduced here which simplify the clock registration process.

In addition to the basic types of clock supported by common clock framework, a Samsung specific representation of the PLL clocks is also introduced.

Both legacy and device tree based Samsung platforms are supported. On legacy platforms, the clocks are statically instantiated and registered with common clock framework. On device tree enabled platforms, the device tree is searched and all clock nodes found are registered. It is also possible to register statically instantiated clocks on device tree enabled platforms.

Quoted 3 lines
Cc Mike Turquette <[email protected]>
Cc Kukjin Kim <[email protected]>

Thanks for the patch. I'm trying to use this series on an Exynos4412 SoC based board. I think it wasn't tested with Exynos4x12 (with FDT support), was it ?

I have a few comments, please see below.

Quoted 142 lines
---
 drivers/clk/Makefile         |    1 +
 drivers/clk/samsung/Makefile |    5 +
 drivers/clk/samsung/clk.c    |  414 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h    |  212 +++++++++++++++++++++
 4 files changed, 632 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/Makefile
 create mode 100644 drivers/clk/samsung/clk.c
 create mode 100644 drivers/clk/samsung/clk.h
drivers/clk/Makefile +1 -0
index 71a25b9..95644e3 100644
@@ -19,6 +19,7 @@ endif
 obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
+obj-$(CONFIG_PLAT_SAMSUNG)	+= samsung/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
drivers/clk/samsung/Makefile new file +5 -0
new file mode 100644
index 0000000..3f926b0
@@ -0,0 +1,5 @@
+#
+# Samsung Clock specific Makefile
+#
+
+obj-$(CONFIG_PLAT_SAMSUNG)	+= clk.o
drivers/clk/samsung/clk.c new file +103 -0
new file mode 100644
index 0000000..f5e269a
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2012 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file includes utility functions to register clocks to common
+ * clock framework for Samsung platforms. This includes an implementation
+ * of Samsung 'pll type' clock to represent the implementation of the
+ * pll found on Samsung platforms. In addition to that, utility functions
+ * to register mux, div, gate and fixed rate types of clocks are included.
+*/
+
+#include <linux/of.h>
+#include "clk.h"
+
+#define MAX_PARENT_CLKS		16
+#define to_clk_pll(_hw) container_of(_hw, struct samsung_pll_clock, hw)
+
+static DEFINE_SPINLOCK(lock);
+static void __iomem *reg_base;
+static void __iomem *reg_fin_pll;
+
+void __init samsung_clk_set_ctrl_base(void __iomem *base)
+{
+	reg_base = base;
+}
+
+void __init samsung_clk_set_finpll_reg(void __iomem *reg)
+{
+	reg_fin_pll = reg;
+}
+
+/* determine the output clock speed of the pll */
+static unsigned long samsung_pll_clock_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
+
+	if (clk_pll->get_rate)
+		return to_clk_pll(hw)->get_rate(parent_rate);
+
+	return 0;
+}
+
+/* round operation not supported */
+static long samsung_pll_clock_round_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long *prate)
+{
+	return samsung_pll_clock_recalc_rate(hw, *prate);
+}
+
+/* set the clock output rate of the pll */
+static int samsung_pll_clock_set_rate(struct clk_hw *hw, unsigned long drate,
+				unsigned long prate)
+{
+	struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
+
+	if (clk_pll->set_rate)
+		return to_clk_pll(hw)->set_rate(drate);
+
+	return 0;
+}
+
+/* clock operations for samsung pll clock type */
+static const struct clk_ops samsung_pll_clock_ops = {
+	.recalc_rate = samsung_pll_clock_recalc_rate,
+	.round_rate = samsung_pll_clock_round_rate,
+	.set_rate = samsung_pll_clock_set_rate,
+};
+
+/* register a samsung pll type clock */
+void __init samsung_clk_register_pll(const char *name, const char **pnames,
+				struct device_node *np,
+				int (*set_rate)(unsigned long rate),
+				unsigned long (*get_rate)(unsigned long rate))
+{
+	struct samsung_pll_clock *clk_pll;
+	struct clk *clk;
+	struct clk_init_data init;
+	int ret;
+
+	clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+	if (!clk_pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return;
+	}
+
+	init.name = name;
+	init.ops = &samsung_pll_clock_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = pnames;
+	init.num_parents = 1;
+
+	clk_pll->set_rate = set_rate;
+	clk_pll->get_rate = get_rate;
+	clk_pll->hw.init = &init;
+
+	/* register the clock */
+	clk = clk_register(NULL, &clk_pll->hw);
+	if (IS_ERR(clk)) {

drivers/clk/samsung/clk.c line 113

Quoted 10 lines
drivers/clk/samsung/clk.c new file +10 -0
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(clk_pll);
+		return;
+	}
+
+#ifdef CONFIG_OF
+	if (np)
+		of_clk_add_provider(np, of_clk_src_simple_get, clk);
+#endif

Is it really required to do clk_register() and of_clk_add_provider() for each single clock ? This seems more heavy than it could be. Looking at drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for whole group of clocks. Also, couldn't we statically define most of the clocks and still register them so they can be used with platforms using FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts /imx28.dtsi), where a clock is specified at consumer device node by a phandle to the clock controller node and a clock index ?

Besides that, what bothers me with in the current approach is the clock consumers being defined through one big data structure together with the actual clocks. Not all clock objects are going to have consumers, some resources are waisted by using flat tables of those big data structure objects. Perhaps we could use two tables, one for the platform clocks and one for the consumers ? These common clock driver is intended to cover all Samsung SoC, I would expect all samsung sub-archs getting converted to use it eventually, with as many of them as possible then reworked to support device tree. It's a lot of work and is going to take some time, but it would be good to have it planned in advance. That said I'm not sure the common samsung clock driver in non-dt variant would be really a temporary thing.

Quoted 270 lines
drivers/clk/samsung/clk.c new file +270 -0
+	/*
+	 * Register a clock lookup for the pll-type clock even if this
+	 * has been instantiated from device tree. This helps to do
+	 * clk_get() lookup on this clock for pruposes of displaying its
+	 * clock speed at boot time.
+	 */
+	ret = clk_register_clkdev(clk, name, NULL);
+	if (ret)
+		pr_err("%s: failed to register clock lookup for %s", __func__,
+				name);
+}
+
+#ifdef CONFIG_OF
+/* register a samsung pll type clock instantiated from device tree */
+void __init samsung_of_clk_register_pll(struct device_node *np)
+{
+	const char *clk_name = np->name;
+	const char *parent_name;
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+	parent_name = of_clk_get_parent_name(np, 0);
+	samsung_clk_register_pll(clk_name, &parent_name, np, NULL, NULL);
+}
+#endif
+
+/*
+ * Allow platform specific implementations to attach set_rate and get_rate
+ * callbacks for the pll type clock. Typical calling sequence..
+ *
+ * struct clk *clk = clk_get(NULL, "pll-clk-name");
+ * samsung_pll_clk_set_cb(clk, pll_set_rate, pll_get_rate);
+ */
+void __init samsung_pll_clk_set_cb(struct clk *clk,
+			int (*set_rate)(unsigned long rate),
+			unsigned long (*get_rate)(unsigned long rate))
+{
+	struct samsung_pll_clock *clk_pll;
+	struct clk_hw *hw = __clk_get_hw(clk);
+
+	clk_pll = to_clk_pll(hw);
+	clk_pll->set_rate = set_rate;
+	clk_pll->get_rate = get_rate;
+}
+
+/* register a list of fixed clocks (used only for non-dt platforms) */
+void __init samsung_clk_register_fixed_rate(
+		struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+		clk = clk_register_fixed_rate(NULL, clk_list->name, NULL,
+				clk_list->flags, clk_list->fixed_rate);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				clk_list->name);
+			continue;
+		}
+
+		/*
+		 * Register a lookup which will help in clk_get() and
+		 * printing the clock rate during clock initialization.
+		 */
+		ret = clk_register_clkdev(clk, clk_list->name,
+						clk_list->dev_name);
+		if (ret)
+			pr_err("clock: failed to register clock lookup for %s",
+				clk_list->name);
+	}
+}
+
+/* register a list of mux clocks */
+void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
+						unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+		clk = clk_register_mux(NULL, clk_list->name,
+			clk_list->parent_names, clk_list->num_parents,
+			clk_list->flags, clk_list->reg, clk_list->shift,
+			clk_list->width, clk_list->mux_flags, &lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+				clk_list->name);
+			continue;
+		}
+
+#ifdef CONFIG_OF
+		if (clk_list->np)
+			of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
+							clk);
+#endif
+
+		ret = clk_register_clkdev(clk, clk_list->name,
+						clk_list->dev_name);
+		if (ret)
+			pr_err("%s: failed to register clock lookup for %s",
+					__func__, clk_list->name);
+
+		if (clk_list->alias) {
+			ret = clk_register_clkdev(clk, clk_list->alias,
+						clk_list->dev_name);
+			if (ret)
+				pr_err("%s: failed to register lookup %s\n",
+					__func__, clk_list->alias);
+		}
+	}
+}
+
+#ifdef CONFIG_OF
+/* register a samsung mux type clock instantiated from device tree */
+void __init samsung_of_clk_register_mux(struct device_node *np)
+{
+	struct samsung_mux_clock mux_clk;
+	const char *clk_name = np->name;
+	const char *parent_names[MAX_PARENT_CLKS];
+	u32 reg_info[3];
+	int idx = 0;
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+	do {
+		/* get names of all parent clocks */
+		parent_names[idx] = of_clk_get_parent_name(np, idx);
+		idx++;
+	} while (parent_names[idx-1]);
+
+	if (of_property_read_u32_array(np, "reg-info", reg_info, 3))
+		pr_err("%s: invalid register info in node\n", __func__);
+
+	mux_clk.name = clk_name;
+	mux_clk.parent_names = parent_names;
+	mux_clk.num_parents = idx - 1;
+	mux_clk.reg = (void __iomem *)(reg_base + reg_info[0]);
+	mux_clk.shift = reg_info[1];
+	mux_clk.width = reg_info[2];
+	mux_clk.dev_name = NULL;
+	mux_clk.flags = 0;
+	mux_clk.mux_flags = 0;
+	mux_clk.alias = NULL;
+	mux_clk.np = np;
+
+	if (!strcmp(mux_clk.name, "fin_pll"))
+		mux_clk.reg = reg_fin_pll;
+
+	samsung_clk_register_mux(&mux_clk, 1);
+}
+#endif
+
+/* register a list of div clocks */
+void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
+						unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+		clk = clk_register_divider(NULL, clk_list->name,
+			clk_list->parent_name, clk_list->flags, clk_list->reg,
+			clk_list->shift, clk_list->width, clk_list->div_flags,
+			&lock);
+		if (IS_ERR(clk)) {
+			pr_err("clock: failed to register clock %s\n",
+				clk_list->name);
+			continue;
+		}
+
+#ifdef CONFIG_OF
+		if (clk_list->np)
+			of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
+							clk);
+#endif
+
+		ret = clk_register_clkdev(clk, clk_list->name,
+						clk_list->dev_name);
+		if (ret)
+			pr_err("%s: failed to register clock lookup for %s",
+					__func__, clk_list->name);
+
+		if (clk_list->alias) {
+			ret = clk_register_clkdev(clk, clk_list->alias,
+						clk_list->dev_name);
+			if (ret)
+				pr_err("%s: failed to register lookup %s\n",
+					__func__, clk_list->alias);
+		}
+	}
+}
+
+#ifdef CONFIG_OF
+/* register a samsung div type clock instantiated from device tree */
+void __init samsung_of_clk_register_div(struct device_node *np)
+{
+	struct samsung_div_clock clk_div;
+	const char *clk_name = np->name;
+	const char *parent_name;
+	u32 reg_info[3];
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (of_property_read_u32_array(np, "reg-info", reg_info, 3))
+		pr_err("%s: invalid register info in node\n", __func__);
+
+	clk_div.name = clk_name;
+	clk_div.parent_name = parent_name;
+	clk_div.reg = (void __iomem *)(reg_base + reg_info[0]);
+	clk_div.shift = reg_info[1];
+	clk_div.width = reg_info[2];
+	clk_div.dev_name = NULL;
+	clk_div.flags = 0;
+	clk_div.div_flags = 0;
+	clk_div.alias = NULL;
+	clk_div.np = np;
+
+	samsung_clk_register_div(&clk_div, 1);
+}
+#endif
+
+/* register a list of gate clocks */
+void __init samsung_clk_register_gate(struct samsung_gate_clock *clk_list,
+						unsigned int nr_clk)
+{
+	struct clk *clk;
+	unsigned int idx, ret;
+
+	for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+		clk = clk_register_gate(NULL, clk_list->name,
+			clk_list->parent_name, clk_list->flags, clk_list->reg,
+			clk_list->bit_idx, clk_list->gate_flags, &lock);
+		if (IS_ERR(clk)) {
+			pr_err("clock: failed to register clock %s\n",
+				clk_list->name);
+			continue;
+		}
+
+#ifdef CONFIG_OF
+		if (clk_list->np)
+			of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
+							clk);
+#endif
+
+		ret = clk_register_clkdev(clk, clk_list->name,
+						clk_list->dev_name);
+		if (ret)
+			pr_err("%s: failed to register clock lookup for %s",
+					__func__, clk_list->name);
+
+		if (clk_list->alias) {
+			ret = clk_register_clkdev(clk, clk_list->alias,
+						clk_list->dev_name);
+			if (ret)
+				pr_err("%s: failed to register lookup %s\n",
+					__func__, clk_list->alias);
+		}
+	}
+}
+
+#ifdef CONFIG_OF
+/* register a samsung gate type clock instantiated from device tree */
+void __init samsung_of_clk_register_gate(struct device_node *np)
+{
+	struct samsung_gate_clock clk_gate;
+	const char *clk_name = np->name;
+	const char *parent_name;
+	u32 reg_info[2];
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+	parent_name = of_clk_get_parent_name(np, 0);

drivers/clk/samsung/clk.c line 394

Quoted 10 lines
drivers/clk/samsung/clk.c new file +10 -0
+	if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
+		pr_err("%s: invalid register info in node\n", __func__);
+
+	clk_gate.name = clk_name;
+	clk_gate.parent_name = parent_name;
+	clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
+	clk_gate.bit_idx = reg_info[1];
+	clk_gate.dev_name = NULL;
+	clk_gate.flags = 0;
+	clk_gate.gate_flags = 0;

Some clocks need CLK_SET_RATE_PARENT for the drivers to work as before. So far it is not set for any mux, div nor gate clock.

drivers/clk/samsung/clk.c line 401

Quoted 7 lines
drivers/clk/samsung/clk.c new file +7 -0
+	clk_gate.alias = NULL;
+	clk_gate.np = np;
+
+	samsung_clk_register_gate(&clk_gate, 1);
+}
+#endif
+

--

Thanks,
Sylwester

#3 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

Hi Sylwester,

Thanks for your comments. As usual, your comments are very helpful.

Quoted 18 lines · Sylwester Nawrocki

Hi Thomas,

Quoted 15 lines · Thomas Abraham

All Samsung platforms include several types of clocks including fixed-rate, mux, divider and gate clock types. There are typically hundreds of such clocks on each of the Samsung platforms. To enable Samsung platforms to register these clocks using the common clock framework, a bunch of utility functions are introduced here which simplify the clock registration process.

In addition to the basic types of clock supported by common clock framework, a Samsung specific representation of the PLL clocks is also introduced.

Both legacy and device tree based Samsung platforms are supported. On legacy platforms, the clocks are statically instantiated and registered with common clock framework. On device tree enabled platforms, the device tree is searched and all clock nodes found are registered. It is also possible to register statically instantiated clocks on device tree enabled platforms.

Quoted 7 lines
Quoted 3 lines
Cc Mike Turquette <[email protected]>
Cc Kukjin Kim <[email protected]>

Thanks for the patch. I'm trying to use this series on an Exynos4412 SoC based board. I think it wasn't tested with Exynos4x12 (with FDT support), was it ?

No, it has not been tested on any Exynos4x12 based board. I have tested it only for Exynos4210 based origen board.

Quoted 150 lines

I have a few comments, please see below.

Quoted 147 lines
---
 drivers/clk/Makefile         |    1 +
 drivers/clk/samsung/Makefile |    5 +
 drivers/clk/samsung/clk.c    |  414 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h    |  212 +++++++++++++++++++++
 4 files changed, 632 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/Makefile
 create mode 100644 drivers/clk/samsung/clk.c
 create mode 100644 drivers/clk/samsung/clk.h
drivers/clk/Makefile +1 -0
index 71a25b9..95644e3 100644
@@ -19,6 +19,7 @@ endif
 obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
 obj-$(CONFIG_ARCH_U8500)     += ux500/
 obj-$(CONFIG_ARCH_VT8500)    += clk-vt8500.o
+obj-$(CONFIG_PLAT_SAMSUNG)   += samsung/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
drivers/clk/samsung/Makefile new file +5 -0
new file mode 100644
index 0000000..3f926b0
@@ -0,0 +1,5 @@
+#
+# Samsung Clock specific Makefile
+#
+
+obj-$(CONFIG_PLAT_SAMSUNG)   += clk.o
drivers/clk/samsung/clk.c new file +108 -0
new file mode 100644
index 0000000..f5e269a
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2012 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file includes utility functions to register clocks to common
+ * clock framework for Samsung platforms. This includes an implementation
+ * of Samsung 'pll type' clock to represent the implementation of the
+ * pll found on Samsung platforms. In addition to that, utility functions
+ * to register mux, div, gate and fixed rate types of clocks are included.
+*/
+
+#include <linux/of.h>
+#include "clk.h"
+
+#define MAX_PARENT_CLKS              16
+#define to_clk_pll(_hw) container_of(_hw, struct samsung_pll_clock, hw)
+
+static DEFINE_SPINLOCK(lock);
+static void __iomem *reg_base;
+static void __iomem *reg_fin_pll;
+
+void __init samsung_clk_set_ctrl_base(void __iomem *base)
+{
+     reg_base = base;
+}
+
+void __init samsung_clk_set_finpll_reg(void __iomem *reg)
+{
+     reg_fin_pll = reg;
+}
+
+/* determine the output clock speed of the pll */
+static unsigned long samsung_pll_clock_recalc_rate(struct clk_hw *hw,
+                             unsigned long parent_rate)
+{
+     struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
+
+     if (clk_pll->get_rate)
+             return to_clk_pll(hw)->get_rate(parent_rate);
+
+     return 0;
+}
+
+/* round operation not supported */
+static long samsung_pll_clock_round_rate(struct clk_hw *hw, unsigned long drate,
+                             unsigned long *prate)
+{
+     return samsung_pll_clock_recalc_rate(hw, *prate);
+}
+
+/* set the clock output rate of the pll */
+static int samsung_pll_clock_set_rate(struct clk_hw *hw, unsigned long drate,
+                             unsigned long prate)
+{
+     struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
+
+     if (clk_pll->set_rate)
+             return to_clk_pll(hw)->set_rate(drate);
+
+     return 0;
+}
+
+/* clock operations for samsung pll clock type */
+static const struct clk_ops samsung_pll_clock_ops = {
+     .recalc_rate = samsung_pll_clock_recalc_rate,
+     .round_rate = samsung_pll_clock_round_rate,
+     .set_rate = samsung_pll_clock_set_rate,
+};
+
+/* register a samsung pll type clock */
+void __init samsung_clk_register_pll(const char *name, const char **pnames,
+                             struct device_node *np,
+                             int (*set_rate)(unsigned long rate),
+                             unsigned long (*get_rate)(unsigned long rate))
+{
+     struct samsung_pll_clock *clk_pll;
+     struct clk *clk;
+     struct clk_init_data init;
+     int ret;
+
+     clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+     if (!clk_pll) {
+             pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+             return;
+     }
+
+     init.name = name;
+     init.ops = &samsung_pll_clock_ops;
+     init.flags = CLK_GET_RATE_NOCACHE;
+     init.parent_names = pnames;
+     init.num_parents = 1;
+
+     clk_pll->set_rate = set_rate;
+     clk_pll->get_rate = get_rate;
+     clk_pll->hw.init = &init;
+
+     /* register the clock */
+     clk = clk_register(NULL, &clk_pll->hw);
+     if (IS_ERR(clk)) {
+             pr_err("%s: failed to register pll clock %s\n", __func__,
+                             name);
+             kfree(clk_pll);
+             return;
+     }
Quoted 8 lines

drivers/clk/samsung/clk.c line 113

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+
+#ifdef CONFIG_OF
+     if (np)
+             of_clk_add_provider(np, of_clk_src_simple_get, clk);
+#endif

Is it really required to do clk_register() and of_clk_add_provider() for each single clock ? This seems more heavy than it could be. Looking at

of_clk_add_provider call for every clock instance is not really required but it does allow platform code to lookup the clock and retrieve/display the clock speed. That was the intention to add a lookup for all the clocks.

Quoted 6 lines

drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for whole group of clocks. Also, couldn't we statically define most of the clocks and still register them so they can be used with platforms using FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts /imx28.dtsi), where a clock is specified at consumer device node by a phandle to the clock controller node and a clock index ?

We could do it that way. I was tempted to list out all the clocks in device tree and then register them so that there is no static definition of the clocks needed. You seem to prefer not to do that. I am fine with either way, static or device tree based registration.

Quoted 13 lines

Besides that, what bothers me with in the current approach is the clock consumers being defined through one big data structure together with the actual clocks. Not all clock objects are going to have consumers, some resources are waisted by using flat tables of those big data structure objects. Perhaps we could use two tables, one for the platform clocks and one for the consumers ? These common clock driver is intended to cover all Samsung SoC, I would expect all samsung sub-archs getting converted to use it eventually, with as many of them as possible then reworked to support device tree. It's a lot of work and is going to take some time, but it would be good to have it planned in advance. That said I'm not sure the common samsung clock driver in non-dt variant would be really a temporary thing.

Non-dt support in Samsung common clock driver will be maintained. But for existing Exynos4 non-dt platforms, it should be possible to convert them to completely device tree based platforms.

Quoted 276 lines
Quoted 276 lines
drivers/clk/samsung/clk.c new file +275 -0
+     /*
+      * Register a clock lookup for the pll-type clock even if this
+      * has been instantiated from device tree. This helps to do
+      * clk_get() lookup on this clock for pruposes of displaying its
+      * clock speed at boot time.
+      */
+     ret = clk_register_clkdev(clk, name, NULL);
+     if (ret)
+             pr_err("%s: failed to register clock lookup for %s", __func__,
+                             name);
+}
+
+#ifdef CONFIG_OF
+/* register a samsung pll type clock instantiated from device tree */
+void __init samsung_of_clk_register_pll(struct device_node *np)
+{
+     const char *clk_name = np->name;
+     const char *parent_name;
+
+     of_property_read_string(np, "clock-output-names", &clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     samsung_clk_register_pll(clk_name, &parent_name, np, NULL, NULL);
+}
+#endif
+
+/*
+ * Allow platform specific implementations to attach set_rate and get_rate
+ * callbacks for the pll type clock. Typical calling sequence..
+ *
+ * struct clk *clk = clk_get(NULL, "pll-clk-name");
+ * samsung_pll_clk_set_cb(clk, pll_set_rate, pll_get_rate);
+ */
+void __init samsung_pll_clk_set_cb(struct clk *clk,
+                     int (*set_rate)(unsigned long rate),
+                     unsigned long (*get_rate)(unsigned long rate))
+{
+     struct samsung_pll_clock *clk_pll;
+     struct clk_hw *hw = __clk_get_hw(clk);
+
+     clk_pll = to_clk_pll(hw);
+     clk_pll->set_rate = set_rate;
+     clk_pll->get_rate = get_rate;
+}
+
+/* register a list of fixed clocks (used only for non-dt platforms) */
+void __init samsung_clk_register_fixed_rate(
+             struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk)
+{
+     struct clk *clk;
+     unsigned int idx, ret;
+
+     for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+             clk = clk_register_fixed_rate(NULL, clk_list->name, NULL,
+                             clk_list->flags, clk_list->fixed_rate);
+             if (IS_ERR(clk)) {
+                     pr_err("%s: failed to register clock %s\n", __func__,
+                             clk_list->name);
+                     continue;
+             }
+
+             /*
+              * Register a lookup which will help in clk_get() and
+              * printing the clock rate during clock initialization.
+              */
+             ret = clk_register_clkdev(clk, clk_list->name,
+                                             clk_list->dev_name);
+             if (ret)
+                     pr_err("clock: failed to register clock lookup for %s",
+                             clk_list->name);
+     }
+}
+
+/* register a list of mux clocks */
+void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
+                                             unsigned int nr_clk)
+{
+     struct clk *clk;
+     unsigned int idx, ret;
+
+     for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+             clk = clk_register_mux(NULL, clk_list->name,
+                     clk_list->parent_names, clk_list->num_parents,
+                     clk_list->flags, clk_list->reg, clk_list->shift,
+                     clk_list->width, clk_list->mux_flags, &lock);
+             if (IS_ERR(clk)) {
+                     pr_err("%s: failed to register clock %s\n", __func__,
+                             clk_list->name);
+                     continue;
+             }
+
+#ifdef CONFIG_OF
+             if (clk_list->np)
+                     of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
+                                                     clk);
+#endif
+
+             ret = clk_register_clkdev(clk, clk_list->name,
+                                             clk_list->dev_name);
+             if (ret)
+                     pr_err("%s: failed to register clock lookup for %s",
+                                     __func__, clk_list->name);
+
+             if (clk_list->alias) {
+                     ret = clk_register_clkdev(clk, clk_list->alias,
+                                             clk_list->dev_name);
+                     if (ret)
+                             pr_err("%s: failed to register lookup %s\n",
+                                     __func__, clk_list->alias);
+             }
+     }
+}
+
+#ifdef CONFIG_OF
+/* register a samsung mux type clock instantiated from device tree */
+void __init samsung_of_clk_register_mux(struct device_node *np)
+{
+     struct samsung_mux_clock mux_clk;
+     const char *clk_name = np->name;
+     const char *parent_names[MAX_PARENT_CLKS];
+     u32 reg_info[3];
+     int idx = 0;
+
+     of_property_read_string(np, "clock-output-names", &clk_name);
+     do {
+             /* get names of all parent clocks */
+             parent_names[idx] = of_clk_get_parent_name(np, idx);
+             idx++;
+     } while (parent_names[idx-1]);
+
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 3))
+             pr_err("%s: invalid register info in node\n", __func__);
+
+     mux_clk.name = clk_name;
+     mux_clk.parent_names = parent_names;
+     mux_clk.num_parents = idx - 1;
+     mux_clk.reg = (void __iomem *)(reg_base + reg_info[0]);
+     mux_clk.shift = reg_info[1];
+     mux_clk.width = reg_info[2];
+     mux_clk.dev_name = NULL;
+     mux_clk.flags = 0;
+     mux_clk.mux_flags = 0;
+     mux_clk.alias = NULL;
+     mux_clk.np = np;
+
+     if (!strcmp(mux_clk.name, "fin_pll"))
+             mux_clk.reg = reg_fin_pll;
+
+     samsung_clk_register_mux(&mux_clk, 1);
+}
+#endif
+
+/* register a list of div clocks */
+void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
+                                             unsigned int nr_clk)
+{
+     struct clk *clk;
+     unsigned int idx, ret;
+
+     for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+             clk = clk_register_divider(NULL, clk_list->name,
+                     clk_list->parent_name, clk_list->flags, clk_list->reg,
+                     clk_list->shift, clk_list->width, clk_list->div_flags,
+                     &lock);
+             if (IS_ERR(clk)) {
+                     pr_err("clock: failed to register clock %s\n",
+                             clk_list->name);
+                     continue;
+             }
+
+#ifdef CONFIG_OF
+             if (clk_list->np)
+                     of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
+                                                     clk);
+#endif
+
+             ret = clk_register_clkdev(clk, clk_list->name,
+                                             clk_list->dev_name);
+             if (ret)
+                     pr_err("%s: failed to register clock lookup for %s",
+                                     __func__, clk_list->name);
+
+             if (clk_list->alias) {
+                     ret = clk_register_clkdev(clk, clk_list->alias,
+                                             clk_list->dev_name);
+                     if (ret)
+                             pr_err("%s: failed to register lookup %s\n",
+                                     __func__, clk_list->alias);
+             }
+     }
+}
+
+#ifdef CONFIG_OF
+/* register a samsung div type clock instantiated from device tree */
+void __init samsung_of_clk_register_div(struct device_node *np)
+{
+     struct samsung_div_clock clk_div;
+     const char *clk_name = np->name;
+     const char *parent_name;
+     u32 reg_info[3];
+
+     of_property_read_string(np, "clock-output-names", &clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 3))
+             pr_err("%s: invalid register info in node\n", __func__);
+
+     clk_div.name = clk_name;
+     clk_div.parent_name = parent_name;
+     clk_div.reg = (void __iomem *)(reg_base + reg_info[0]);
+     clk_div.shift = reg_info[1];
+     clk_div.width = reg_info[2];
+     clk_div.dev_name = NULL;
+     clk_div.flags = 0;
+     clk_div.div_flags = 0;
+     clk_div.alias = NULL;
+     clk_div.np = np;
+
+     samsung_clk_register_div(&clk_div, 1);
+}
+#endif
+
+/* register a list of gate clocks */
+void __init samsung_clk_register_gate(struct samsung_gate_clock *clk_list,
+                                             unsigned int nr_clk)
+{
+     struct clk *clk;
+     unsigned int idx, ret;
+
+     for (idx = 0; idx < nr_clk; idx++, clk_list++) {
+             clk = clk_register_gate(NULL, clk_list->name,
+                     clk_list->parent_name, clk_list->flags, clk_list->reg,
+                     clk_list->bit_idx, clk_list->gate_flags, &lock);
+             if (IS_ERR(clk)) {
+                     pr_err("clock: failed to register clock %s\n",
+                             clk_list->name);
+                     continue;
+             }
+
+#ifdef CONFIG_OF
+             if (clk_list->np)
+                     of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
+                                                     clk);
+#endif
+
+             ret = clk_register_clkdev(clk, clk_list->name,
+                                             clk_list->dev_name);
+             if (ret)
+                     pr_err("%s: failed to register clock lookup for %s",
+                                     __func__, clk_list->name);
+
+             if (clk_list->alias) {
+                     ret = clk_register_clkdev(clk, clk_list->alias,
+                                             clk_list->dev_name);
+                     if (ret)
+                             pr_err("%s: failed to register lookup %s\n",
+                                     __func__, clk_list->alias);
+             }
+     }
+}
+
+#ifdef CONFIG_OF
+/* register a samsung gate type clock instantiated from device tree */
+void __init samsung_of_clk_register_gate(struct device_node *np)
+{
+     struct samsung_gate_clock clk_gate;
+     const char *clk_name = np->name;
+     const char *parent_name;
+     u32 reg_info[2];
+
+     of_property_read_string(np, "clock-output-names", &clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
+             pr_err("%s: invalid register info in node\n", __func__);
+
+     clk_gate.name = clk_name;
+     clk_gate.parent_name = parent_name;
Quoted 8 lines

drivers/clk/samsung/clk.c line 394

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+     clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
+     clk_gate.bit_idx = reg_info[1];
+     clk_gate.dev_name = NULL;
+     clk_gate.flags = 0;
+     clk_gate.gate_flags = 0;

Some clocks need CLK_SET_RATE_PARENT for the drivers to work as before. So far it is not set for any mux, div nor gate clock.

Ok. I will fix this.

So about the static vs device tree based clock registration, what would you suggest?

Thanks,
Thomas.

Quoted 14 lines

drivers/clk/samsung/clk.c line 401

Quoted 8 lines
drivers/clk/samsung/clk.c new file +7 -0
+     clk_gate.alias = NULL;
+     clk_gate.np = np;
+
+     samsung_clk_register_gate(&clk_gate, 1);
+}
+#endif
+

--

Thanks,
Sylwester

#4 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

Hi Thomas,

Quoted 3 lines · Thomas Abraham

Hi Sylwester,

Thanks for your comments. As usual, your comments are very helpful.

Thanks.

Quoted 23 lines · Sylwester Nawrocki
Quoted 22 lines

Hi Thomas,

Quoted 18 lines · Thomas Abraham

All Samsung platforms include several types of clocks including fixed-rate, mux, divider and gate clock types. There are typically hundreds of such clocks on each of the Samsung platforms. To enable Samsung platforms to register these clocks using the common clock framework, a bunch of utility functions are introduced here which simplify the clock registration process.

In addition to the basic types of clock supported by common clock framework, a Samsung specific representation of the PLL clocks is also introduced.

Both legacy and device tree based Samsung platforms are supported. On legacy platforms, the clocks are statically instantiated and registered with common clock framework. On device tree enabled platforms, the device tree is searched and all clock nodes found are registered. It is also possible to register statically instantiated clocks on device tree enabled platforms.

Cc Mike Turquette<[email protected]>
Cc Kukjin Kim<[email protected]>
Quoted 6 lines
Quoted 3 lines

Thanks for the patch. I'm trying to use this series on an Exynos4412 SoC based board. I think it wasn't tested with Exynos4x12 (with FDT support), was it ?

No, it has not been tested on any Exynos4x12 based board. I have tested it only for Exynos4210 based origen board.

OK, thanks. I've had some issues with the root clocks on Exynos4412 and I put this on a back burner for a while. I plan to get back to this, possibly after ELCE/LinuxCon.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
---
  drivers/clk/Makefile         |    1 +
  drivers/clk/samsung/Makefile |    5 +
  drivers/clk/samsung/clk.c    |  414 ++++++++++++++++++++++++++++++++++++++++++
  drivers/clk/samsung/clk.h    |  212 +++++++++++++++++++++
  4 files changed, 632 insertions(+), 0 deletions(-)

create mode 100644 drivers/clk/samsung/Makefile
create mode 100644 drivers/clk/samsung/clk.c
create mode 100644 drivers/clk/samsung/clk.h

...

Quoted 44 lines
Quoted 35 lines
Quoted 35 lines
drivers/clk/samsung/clk.c new file +35 -0
+/* register a samsung pll type clock */
+void __init samsung_clk_register_pll(const char *name, const char **pnames,
+                             struct device_node *np,
+                             int (*set_rate)(unsigned long rate),
+                             unsigned long (*get_rate)(unsigned long rate))
+{
+     struct samsung_pll_clock *clk_pll;
+     struct clk *clk;
+     struct clk_init_data init;
+     int ret;
+
+     clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+     if (!clk_pll) {
+             pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+             return;
+     }
+
+     init.name = name;
+     init.ops =&samsung_pll_clock_ops;
+     init.flags = CLK_GET_RATE_NOCACHE;
+     init.parent_names = pnames;
+     init.num_parents = 1;
+
+     clk_pll->set_rate = set_rate;
+     clk_pll->get_rate = get_rate;
+     clk_pll->hw.init =&init;
+
+     /* register the clock */
+     clk = clk_register(NULL,&clk_pll->hw);
+     if (IS_ERR(clk)) {
+             pr_err("%s: failed to register pll clock %s\n", __func__,
+                             name);
+             kfree(clk_pll);
+             return;
+     }
Quoted 8 lines

drivers/clk/samsung/clk.c line 113

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+
+#ifdef CONFIG_OF
+     if (np)
+             of_clk_add_provider(np, of_clk_src_simple_get, clk);
+#endif

Is it really required to do clk_register() and of_clk_add_provider() for each single clock ? This seems more heavy than it could be. Looking at

Quoted 4 lines

of_clk_add_provider call for every clock instance is not really required but it does allow platform code to lookup the clock and retrieve/display the clock speed. That was the intention to add a lookup for all the clocks.

Hmm, do you mean calling clk_get() with NULL 'dev' argument ? It's probably not a big deal to look up the clocks root node and then use of_clk_get() function to find required clock ?

Quoted 11 lines
Quoted 6 lines

drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for whole group of clocks. Also, couldn't we statically define most of the clocks and still register them so they can be used with platforms using FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts /imx28.dtsi), where a clock is specified at consumer device node by a phandle to the clock controller node and a clock index ?

We could do it that way. I was tempted to list out all the clocks in device tree and then register them so that there is no static definition of the clocks needed. You seem to prefer not to do that. I am fine with either way, static or device tree based registration.

Ok, it's also worth noting that clk_get() would have been more expensive when there would be a need to iterate over large number of clock providers. Indexed look up might be a better alternative.

Exynos SoCs have fairly complex clock tree structure, I personally do find it harder to understand from a bit bulky description in form of a device tree node list. Comparing to the original Samsung clock API there is now more clock objects, since, e.g. single struct clk_clksrc is now represented by mux, div and gate clock group, which makes things slightly more complicated, i.e. there is even more clocks to be listed.

Quoted 13 lines
Quoted 4 lines

Besides that, what bothers me with in the current approach is the clock consumers being defined through one big data structure together with the actual clocks. Not all clock objects are going to have consumers, some resources are waisted by using flat tables of those

Quoted 8 lines

big data structure objects. Perhaps we could use two tables, one for the platform clocks and one for the consumers ? These common clock driver is intended to cover all Samsung SoC, I would expect all samsung sub-archs getting converted to use it eventually, with as many of them as possible then reworked to support device tree. It's a lot of work and is going to take some time, but it would be good to have it planned in advance. That said I'm not sure the common samsung clock driver in non-dt variant would be really a temporary thing.

Quoted 3 lines

Non-dt support in Samsung common clock driver will be maintained. But for existing Exynos4 non-dt platforms, it should be possible to convert them to completely device tree based platforms.

OK, let's then focus on device tree support for exynos4+ SoCs. I hope we could have the clocks statically defined and still freely accessible in the device tree.

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
drivers/clk/samsung/clk.c new file +11 -0
+     /*
+      * Register a clock lookup for the pll-type clock even if this
+      * has been instantiated from device tree. This helps to do
+      * clk_get() lookup on this clock for pruposes of displaying its
+      * clock speed at boot time.
+      */
+     ret = clk_register_clkdev(clk, name, NULL);
+     if (ret)
+             pr_err("%s: failed to register clock lookup for %s", __func__,
+                             name);
+}

...

Quoted 26 lines
Quoted 17 lines
Quoted 17 lines
drivers/clk/samsung/clk.c new file +17 -0
+
+#ifdef CONFIG_OF
+/* register a samsung gate type clock instantiated from device tree */
+void __init samsung_of_clk_register_gate(struct device_node *np)
+{
+     struct samsung_gate_clock clk_gate;
+     const char *clk_name = np->name;
+     const char *parent_name;
+     u32 reg_info[2];
+
+     of_property_read_string(np, "clock-output-names",&clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
+             pr_err("%s: invalid register info in node\n", __func__);
+
+     clk_gate.name = clk_name;
+     clk_gate.parent_name = parent_name;
Quoted 8 lines

drivers/clk/samsung/clk.c line 394

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+     clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
+     clk_gate.bit_idx = reg_info[1];
+     clk_gate.dev_name = NULL;
+     clk_gate.flags = 0;
+     clk_gate.gate_flags = 0;

Some clocks need CLK_SET_RATE_PARENT for the drivers to work as before. So far it is not set for any mux, div nor gate clock.

Quoted 4 lines

Ok. I will fix this.

So about the static vs device tree based clock registration, what would you suggest?

Defining the clocks statically has my preference, it would be nice to hear more opinions on that though. I think on a heavily utilised SoC the list of clock nodes could have grown significantly. And with preprocessor support at the dt compiler (not sure if it is already there) indexed clock definitions could be made more explicit.

These are roughly our conclusions from discussing this patch series with Tomasz F.

--
Thanks,
Sylwester

#5 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

Hi Thomas, Sylwester,

Quoted 46 lines · On Wednesday 31 of October 2012 00:10:24 Sylwester Nawrocki wrote:
Quoted 46 lines
Quoted 45 lines
Quoted 32 lines
(quoted diff) +2 -0
+/* register a samsung pll type clock */
+void __init samsung_clk_register_pll(const char *name, const char

**pnames, + struct device_node *np,

(quoted diff) +2 -0
+                             int (*set_rate)(unsigned long rate),
+                             unsigned long (*get_rate)(unsigned long

rate)) +{

drivers/clk/samsung/clk.c new file +8 -0
+     struct samsung_pll_clock *clk_pll;
+     struct clk *clk;
+     struct clk_init_data init;
+     int ret;
+
+     clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+     if (!clk_pll) {
+             pr_err("%s: could not allocate pll clk %s\n", __func__,

name); + return;

drivers/clk/samsung/clk.c new file +16 -0
+     }
+
+     init.name = name;
+     init.ops =&samsung_pll_clock_ops;
+     init.flags = CLK_GET_RATE_NOCACHE;
+     init.parent_names = pnames;
+     init.num_parents = 1;
+
+     clk_pll->set_rate = set_rate;
+     clk_pll->get_rate = get_rate;
+     clk_pll->hw.init =&init;
+
+     /* register the clock */
+     clk = clk_register(NULL,&clk_pll->hw);
+     if (IS_ERR(clk)) {
+             pr_err("%s: failed to register pll clock %s\n",

__func__,

drivers/clk/samsung/clk.c line 113

Quoted 9 lines
drivers/clk/samsung/clk.c new file +9 -0
+                             name);
+             kfree(clk_pll);
+             return;
+     }
+
+#ifdef CONFIG_OF
+     if (np)
+             of_clk_add_provider(np, of_clk_src_simple_get, clk);
+#endif

Is it really required to do clk_register() and of_clk_add_provider() for
each single clock ? This seems more heavy than it could be. Looking at

Quoted 4 lines
Quoted 4 lines

of_clk_add_provider call for every clock instance is not really required but it does allow platform code to lookup the clock and retrieve/display the clock speed. That was the intention to add a lookup for all the clocks.

I'm not really sure if displaying clock speed is really a good justification for increasing the list of system clocks almost by a factor of three. This will make clock lookup a bit heavy.

You might display speed of several most important clocks directly from the samsung clk driver using internal data, without the need of involving generic clock lookup for this purpose.

Quoted 4 lines

Hmm, do you mean calling clk_get() with NULL 'dev' argument ? It's probably not a big deal to look up the clocks root node and then use of_clk_get() function to find required clock ?

I believe that the intention was for it to work on non-DT platforms as well. However I might have misunderstood your suggestion, could you elaborate?

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for
whole group of clocks. Also, couldn't we statically define most of the clocks and still register them so they can be used with platforms using
FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts /imx28.dtsi), where a clock is specified at consumer device node by a phandle to the clock controller node and a clock index ?

Quoted 8 lines
Quoted 4 lines

We could do it that way. I was tempted to list out all the clocks in device tree and then register them so that there is no static definition of the clocks needed. You seem to prefer not to do that. I am fine with either way, static or device tree based registration.

Ok, it's also worth noting that clk_get() would have been more expensive when there would be a need to iterate over large number of clock providers. Indexed look up might be a better alternative.

I'm definitely for indexed lookup. With the ability to define constants in device tree sources the main drawback of this solution being less readable now disappeared and everything left are advantages.

Quoted 6 lines

Exynos SoCs have fairly complex clock tree structure, I personally do find it harder to understand from a bit bulky description in form of a device tree node list. Comparing to the original Samsung clock API there is now more clock objects, since, e.g. single struct clk_clksrc is now represented by mux, div and gate clock group, which makes things slightly more complicated, i.e. there is even more clocks to be listed.

If it's about readability I tend to disagree. I find device tree much more readable as a way of describing hardware than hardcoded data structures, often using complex macros to keep the definitions short.

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines

Besides that, what bothers me with in the current approach is the clock consumers being defined through one big data structure together with the actual clocks. Not all clock objects are going to have consumers, some resources are waisted by using flat tables of those big data structure objects. Perhaps we could use two tables, one for the
platform clocks and one for the consumers ? These common clock driver is intended to cover all Samsung SoC, I would expect all samsung sub-archs getting converted to use it eventually, with as many of them as possible then reworked to support device tree. It's a lot of work and is going to take some time, but it would be good to have it planned
in advance. That said I'm not sure the common samsung clock driver in non-dt variant would be really a temporary thing.

Quoted 7 lines
Quoted 3 lines

Non-dt support in Samsung common clock driver will be maintained. But for existing Exynos4 non-dt platforms, it should be possible to convert them to completely device tree based platforms.

OK, let's then focus on device tree support for exynos4+ SoCs. I hope we could have the clocks statically defined and still freely accessible in the device tree.

Using the approach with indexed clocks inside a single provider would allow to reuse the same internal SoC-specific data for both DT and non-DT variants, without any data duplication. This is definitely an advantage.

Quoted 33 lines
Quoted 28 lines
Quoted 19 lines
Quoted 19 lines
drivers/clk/samsung/clk.c new file +3 -0
+
+#ifdef CONFIG_OF
+/* register a samsung gate type clock instantiated from device tree

*/

drivers/clk/samsung/clk.c new file +11 -0
+void __init samsung_of_clk_register_gate(struct device_node *np)
+{
+     struct samsung_gate_clock clk_gate;
+     const char *clk_name = np->name;
+     const char *parent_name;
+     u32 reg_info[2];
+
+     of_property_read_string(np, "clock-output-names",&clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
+             pr_err("%s: invalid register info in node\n",

__func__);

drivers/clk/samsung/clk.c new file +3 -0
+
+     clk_gate.name = clk_name;
+     clk_gate.parent_name = parent_name;
Quoted 8 lines

drivers/clk/samsung/clk.c line 394

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+     clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
+     clk_gate.bit_idx = reg_info[1];
+     clk_gate.dev_name = NULL;
+     clk_gate.flags = 0;
+     clk_gate.gate_flags = 0;

Some clocks need CLK_SET_RATE_PARENT for the drivers to work as before. So far it is not set for any mux, div nor gate clock.

Quoted 4 lines

Ok. I will fix this.

So about the static vs device tree based clock registration, what would you suggest?

Quoted 8 lines

Defining the clocks statically has my preference, it would be nice to hear more opinions on that though. I think on a heavily utilised SoC the list of clock nodes could have grown significantly. And with preprocessor support at the dt compiler (not sure if it is already there) indexed clock definitions could be made more explicit.

These are roughly our conclusions from discussing this patch series with Tomasz F.

Yes, as I said, I'm definitely for the single clock provider approach (aka imx-like approach).

Best regards,
Tomasz Figa

#6 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

Hi Tomasz,

Quoted 54 lines · Tomasz Figa

Hi Thomas, Sylwester,

Quoted 46 lines · On Wednesday 31 of October 2012 00:10:24 Sylwester Nawrocki wrote:
Quoted 46 lines
Quoted 45 lines
Quoted 32 lines
(quoted diff) +2 -0
+/* register a samsung pll type clock */
+void __init samsung_clk_register_pll(const char *name, const char

**pnames, + struct device_node *np,

(quoted diff) +2 -0
+                             int (*set_rate)(unsigned long rate),
+                             unsigned long (*get_rate)(unsigned long

rate)) +{

drivers/clk/samsung/clk.c new file +8 -0
+     struct samsung_pll_clock *clk_pll;
+     struct clk *clk;
+     struct clk_init_data init;
+     int ret;
+
+     clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+     if (!clk_pll) {
+             pr_err("%s: could not allocate pll clk %s\n", __func__,

name); + return;

drivers/clk/samsung/clk.c new file +16 -0
+     }
+
+     init.name = name;
+     init.ops =&samsung_pll_clock_ops;
+     init.flags = CLK_GET_RATE_NOCACHE;
+     init.parent_names = pnames;
+     init.num_parents = 1;
+
+     clk_pll->set_rate = set_rate;
+     clk_pll->get_rate = get_rate;
+     clk_pll->hw.init =&init;
+
+     /* register the clock */
+     clk = clk_register(NULL,&clk_pll->hw);
+     if (IS_ERR(clk)) {
+             pr_err("%s: failed to register pll clock %s\n",

__func__,

drivers/clk/samsung/clk.c line 113

Quoted 9 lines
drivers/clk/samsung/clk.c new file +9 -0
+                             name);
+             kfree(clk_pll);
+             return;
+     }
+
+#ifdef CONFIG_OF
+     if (np)
+             of_clk_add_provider(np, of_clk_src_simple_get, clk);
+#endif

Is it really required to do clk_register() and of_clk_add_provider() for
each single clock ? This seems more heavy than it could be. Looking at

Quoted 4 lines
Quoted 4 lines

of_clk_add_provider call for every clock instance is not really required but it does allow platform code to lookup the clock and retrieve/display the clock speed. That was the intention to add a lookup for all the clocks.

Quoted 7 lines

I'm not really sure if displaying clock speed is really a good justification for increasing the list of system clocks almost by a factor of three. This will make clock lookup a bit heavy.

You might display speed of several most important clocks directly from the samsung clk driver using internal data, without the need of involving generic clock lookup for this purpose.

Ok. But that would mean that we implment the clk_get_rate() function for such clocks again. For example, to get the rate of the aclk_200 clock, its parent clock would have to be divided and then displayed. But it was easier to just use the clk_get api. But yes I agree, this is not a compelling reason to register all the clocks.

Quoted 25 lines
Quoted 5 lines

Hmm, do you mean calling clk_get() with NULL 'dev' argument ? It's probably not a big deal to look up the clocks root node and then use of_clk_get() function to find required clock ?

I believe that the intention was for it to work on non-DT platforms as well. However I might have misunderstood your suggestion, could you elaborate?

Quoted 15 lines
Quoted 14 lines
Quoted 9 lines

drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for
whole group of clocks. Also, couldn't we statically define most of the clocks and still register them so they can be used with platforms using
FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts /imx28.dtsi), where a clock is specified at consumer device node by a phandle to the clock controller node and a clock index ?

We could do it that way. I was tempted to list out all the clocks in device tree and then register them so that there is no static definition of the clocks needed. You seem to prefer not to do that. I am fine with either way, static or device tree based registration.

Quoted 7 lines
Quoted 3 lines

Ok, it's also worth noting that clk_get() would have been more expensive when there would be a need to iterate over large number of clock providers. Indexed look up might be a better alternative.

I'm definitely for indexed lookup. With the ability to define constants in device tree sources the main drawback of this solution being less readable now disappeared and everything left are advantages.

Ok.

Quoted 31 lines
Quoted 7 lines

Exynos SoCs have fairly complex clock tree structure, I personally do find it harder to understand from a bit bulky description in form of a device tree node list. Comparing to the original Samsung clock API there is now more clock objects, since, e.g. single struct clk_clksrc is now represented by mux, div and gate clock group, which makes things slightly more complicated, i.e. there is even more clocks to be listed.

If it's about readability I tend to disagree. I find device tree much more readable as a way of describing hardware than hardcoded data structures, often using complex macros to keep the definitions short.

Quoted 19 lines
Quoted 18 lines
Quoted 6 lines

Besides that, what bothers me with in the current approach is the clock consumers being defined through one big data structure together with the actual clocks. Not all clock objects are going to have consumers, some resources are waisted by using flat tables of those big data structure objects. Perhaps we could use two tables, one for the

Quoted 8 lines

platform clocks and one for the consumers ? These common clock driver is intended to cover all Samsung SoC, I would expect all samsung sub-archs getting converted to use it eventually, with as many of them as possible then reworked to support device tree. It's a lot of work and is going to take some time, but it would be good to have it planned
in advance. That said I'm not sure the common samsung clock driver in non-dt variant would be really a temporary thing.

Non-dt support in Samsung common clock driver will be maintained. But for existing Exynos4 non-dt platforms, it should be possible to convert them to completely device tree based platforms.

Quoted 7 lines
Quoted 3 lines

OK, let's then focus on device tree support for exynos4+ SoCs. I hope we could have the clocks statically defined and still freely accessible in the device tree.

Using the approach with indexed clocks inside a single provider would allow to reuse the same internal SoC-specific data for both DT and non-DT variants, without any data duplication. This is definitely an advantage.

Ok.

Quoted 40 lines
Quoted 40 lines
Quoted 29 lines
Quoted 20 lines
Quoted 20 lines
drivers/clk/samsung/clk.c new file +3 -0
+
+#ifdef CONFIG_OF
+/* register a samsung gate type clock instantiated from device tree

*/

drivers/clk/samsung/clk.c new file +11 -0
+void __init samsung_of_clk_register_gate(struct device_node *np)
+{
+     struct samsung_gate_clock clk_gate;
+     const char *clk_name = np->name;
+     const char *parent_name;
+     u32 reg_info[2];
+
+     of_property_read_string(np, "clock-output-names",&clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
+             pr_err("%s: invalid register info in node\n",

__func__);

drivers/clk/samsung/clk.c new file +3 -0
+
+     clk_gate.name = clk_name;
+     clk_gate.parent_name = parent_name;
Quoted 8 lines

drivers/clk/samsung/clk.c line 394

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+     clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
+     clk_gate.bit_idx = reg_info[1];
+     clk_gate.dev_name = NULL;
+     clk_gate.flags = 0;
+     clk_gate.gate_flags = 0;

Some clocks need CLK_SET_RATE_PARENT for the drivers to work as before. So far it is not set for any mux, div nor gate clock.

Quoted 4 lines

Ok. I will fix this.

So about the static vs device tree based clock registration, what would you suggest?

Defining the clocks statically has my preference, it would be nice to hear more opinions on that though. I think on a heavily utilised SoC the list of clock nodes could have grown significantly. And with preprocessor support at the dt compiler (not sure if it is already there) indexed clock definitions could be made more explicit.

Quoted 5 lines
Quoted 2 lines

These are roughly our conclusions from discussing this patch series with Tomasz F.

Yes, as I said, I'm definitely for the single clock provider approach (aka imx-like approach).

Ok. Thanks for your comments. I will redo this patch series.

Thanks,
Thomas.

Quoted 4 lines

Best regards,
Tomasz Figa

#7 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

In reply to Sylwester Nawrocki

Hi Sylwester,

Quoted 35 lines · Sylwester Nawrocki

Hi Thomas,

Quoted 3 lines · Thomas Abraham

Hi Sylwester,

Thanks for your comments. As usual, your comments are very helpful.

Thanks.

Quoted 27 lines · Sylwester Nawrocki
Quoted 25 lines

Hi Thomas,

Quoted 15 lines · Thomas Abraham

All Samsung platforms include several types of clocks including fixed-rate, mux, divider and gate clock types. There are typically hundreds of such clocks on each of the Samsung platforms. To enable Samsung platforms to register these clocks using the common clock framework, a bunch of utility functions are introduced here which simplify the clock registration process.

In addition to the basic types of clock supported by common clock framework, a Samsung specific representation of the PLL clocks is also introduced.

Both legacy and device tree based Samsung platforms are supported. On legacy platforms, the clocks are statically instantiated and registered with common clock framework. On device tree enabled platforms, the device tree is searched and all clock nodes found are registered. It is also possible to register statically instantiated clocks on device tree enabled platforms.

Quoted 3 lines
Cc Mike Turquette<[email protected]>
Cc Kukjin Kim<[email protected]>

Thanks for the patch. I'm trying to use this series on an Exynos4412 SoC based board. I think it wasn't tested with Exynos4x12 (with FDT support), was it ?

Quoted 6 lines
Quoted 2 lines

No, it has not been tested on any Exynos4x12 based board. I have tested it only for Exynos4210 based origen board.

OK, thanks. I've had some issues with the root clocks on Exynos4412 and I put this on a back burner for a while. I plan to get back to this, possibly after ELCE/LinuxCon.

Ok.

Quoted 55 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
---
  drivers/clk/Makefile         |    1 +
  drivers/clk/samsung/Makefile |    5 +
  drivers/clk/samsung/clk.c    |  414 ++++++++++++++++++++++++++++++++++++++++++
  drivers/clk/samsung/clk.h    |  212 +++++++++++++++++++++
  4 files changed, 632 insertions(+), 0 deletions(-)

create mode 100644 drivers/clk/samsung/Makefile
create mode 100644 drivers/clk/samsung/clk.c
create mode 100644 drivers/clk/samsung/clk.h

...

Quoted 44 lines
Quoted 43 lines
Quoted 30 lines
drivers/clk/samsung/clk.c new file +30 -0
+/* register a samsung pll type clock */
+void __init samsung_clk_register_pll(const char *name, const char **pnames,
+                             struct device_node *np,
+                             int (*set_rate)(unsigned long rate),
+                             unsigned long (*get_rate)(unsigned long rate))
+{
+     struct samsung_pll_clock *clk_pll;
+     struct clk *clk;
+     struct clk_init_data init;
+     int ret;
+
+     clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
+     if (!clk_pll) {
+             pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+             return;
+     }
+
+     init.name = name;
+     init.ops =&samsung_pll_clock_ops;
+     init.flags = CLK_GET_RATE_NOCACHE;
+     init.parent_names = pnames;
+     init.num_parents = 1;
+
+     clk_pll->set_rate = set_rate;
+     clk_pll->get_rate = get_rate;
+     clk_pll->hw.init =&init;
+
+     /* register the clock */
+     clk = clk_register(NULL,&clk_pll->hw);
+     if (IS_ERR(clk)) {

drivers/clk/samsung/clk.c line 113

Quoted 10 lines
drivers/clk/samsung/clk.c new file +10 -0
+             pr_err("%s: failed to register pll clock %s\n", __func__,
+                             name);
+             kfree(clk_pll);
+             return;
+     }
+
+#ifdef CONFIG_OF
+     if (np)
+             of_clk_add_provider(np, of_clk_src_simple_get, clk);
+#endif

Is it really required to do clk_register() and of_clk_add_provider() for each single clock ? This seems more heavy than it could be. Looking at

Quoted 8 lines
Quoted 4 lines

of_clk_add_provider call for every clock instance is not really required but it does allow platform code to lookup the clock and retrieve/display the clock speed. That was the intention to add a lookup for all the clocks.

Hmm, do you mean calling clk_get() with NULL 'dev' argument ? It's probably not a big deal to look up the clocks root node and then use of_clk_get() function to find required clock ?

Yes, I was referring to calling clk_get() with NULL 'dev' argument. Usually, at boot, the clock frequency of some of the system clocks (such as aclk_200) are displayed. So all the clocks were registered using clk_register allowing clock frequency of any the clock to be retrieved using clk_get.

Your suggestion to use of_clk_get assumes the clock implementation follows the imx style, which was not way used in this patch series. And then there is this problem of supporting non-dt platforms as well.

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for whole group of clocks. Also, couldn't we statically define most of the clocks and still register them so they can be used with platforms using FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts /imx28.dtsi), where a clock is specified at consumer device node by a phandle to the clock controller node and a clock index ?

Quoted 8 lines
Quoted 4 lines

We could do it that way. I was tempted to list out all the clocks in device tree and then register them so that there is no static definition of the clocks needed. You seem to prefer not to do that. I am fine with either way, static or device tree based registration.

Ok, it's also worth noting that clk_get() would have been more expensive when there would be a need to iterate over large number of clock providers. Indexed look up might be a better alternative.

Yes, true.

Quoted 8 lines

Exynos SoCs have fairly complex clock tree structure, I personally do find it harder to understand from a bit bulky description in form of a device tree node list. Comparing to the original Samsung clock API there is now more clock objects, since, e.g. single struct clk_clksrc is now represented by mux, div and gate clock group, which makes things slightly more complicated, i.e. there is even more clocks to be listed.

Ok.

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines

Besides that, what bothers me with in the current approach is the clock consumers being defined through one big data structure together with the actual clocks. Not all clock objects are going to have consumers, some resources are waisted by using flat tables of those big data structure objects. Perhaps we could use two tables, one for the platform clocks and one for the consumers ? These common clock driver is intended to cover all Samsung SoC, I would expect all samsung sub-archs getting converted to use it eventually, with as many of them as possible then reworked to support device tree. It's a lot of work and is going to take some time, but it would be good to have it planned in advance. That said I'm not sure the common samsung clock driver in non-dt variant would be really a temporary thing.

Quoted 7 lines
Quoted 3 lines

Non-dt support in Samsung common clock driver will be maintained. But for existing Exynos4 non-dt platforms, it should be possible to convert them to completely device tree based platforms.

OK, let's then focus on device tree support for exynos4+ SoCs. I hope we could have the clocks statically defined and still freely accessible in the device tree.

Ok. I will implement it as you mentioned.

Quoted 44 lines
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
drivers/clk/samsung/clk.c new file +11 -0
+     /*
+      * Register a clock lookup for the pll-type clock even if this
+      * has been instantiated from device tree. This helps to do
+      * clk_get() lookup on this clock for pruposes of displaying its
+      * clock speed at boot time.
+      */
+     ret = clk_register_clkdev(clk, name, NULL);
+     if (ret)
+             pr_err("%s: failed to register clock lookup for %s", __func__,
+                             name);
+}

...

Quoted 26 lines
Quoted 17 lines
Quoted 17 lines
drivers/clk/samsung/clk.c new file +17 -0
+
+#ifdef CONFIG_OF
+/* register a samsung gate type clock instantiated from device tree */
+void __init samsung_of_clk_register_gate(struct device_node *np)
+{
+     struct samsung_gate_clock clk_gate;
+     const char *clk_name = np->name;
+     const char *parent_name;
+     u32 reg_info[2];
+
+     of_property_read_string(np, "clock-output-names",&clk_name);
+     parent_name = of_clk_get_parent_name(np, 0);
+     if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
+             pr_err("%s: invalid register info in node\n", __func__);
+
+     clk_gate.name = clk_name;
+     clk_gate.parent_name = parent_name;
Quoted 8 lines

drivers/clk/samsung/clk.c line 394

Quoted 5 lines
drivers/clk/samsung/clk.c new file +5 -0
+     clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
+     clk_gate.bit_idx = reg_info[1];
+     clk_gate.dev_name = NULL;
+     clk_gate.flags = 0;
+     clk_gate.gate_flags = 0;

Some clocks need CLK_SET_RATE_PARENT for the drivers to work as before. So far it is not set for any mux, div nor gate clock.

Quoted 4 lines

Ok. I will fix this.

So about the static vs device tree based clock registration, what would you suggest?

Quoted 8 lines

Defining the clocks statically has my preference, it would be nice to hear more opinions on that though. I think on a heavily utilised SoC the list of clock nodes could have grown significantly. And with preprocessor support at the dt compiler (not sure if it is already there) indexed clock definitions could be made more explicit.

These are roughly our conclusions from discussing this patch series with Tomasz F.

Ok. Thanks for your comments. I will redo this patch series and post them.

Thanks,
Thomas.

Quoted 4 lines

--
Thanks,
Sylwester

#8 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

In reply to Thomas Abraham

Hi Thomas,

Quoting Thomas Abraham (2012-10-07 10:10:51)

drivers/clk/samsung/clk.c line 43

Quoted 8 lines
drivers/clk/samsung/clk.c new file +8 -0
+/* determine the output clock speed of the pll */
+static unsigned long samsung_pll_clock_recalc_rate(struct clk_hw *hw,
+                               unsigned long parent_rate)
+{
+       struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
+
+       if (clk_pll->get_rate)
+               return to_clk_pll(hw)->get_rate(parent_rate);

Why the extra indirection? Does your samsung_pll_clock abstract several different PLL implementations (with separate clock ops)? If so, why not make a unique struct for each PLL type?

drivers/clk/samsung/clk.c line 52

Quoted 9 lines
drivers/clk/samsung/clk.c new file +9 -0
+
+       return 0;
+}
+
+/* round operation not supported */
+static long samsung_pll_clock_round_rate(struct clk_hw *hw, unsigned long drate,
+                               unsigned long *prate)
+{
+       return samsung_pll_clock_recalc_rate(hw, *prate);

Why is round_rate not supported? How is returning the recalculated rate the right thing here?

Quoted 8 lines
drivers/clk/samsung/clk.c new file +8 -0
+/*
+ * Allow platform specific implementations to attach set_rate and get_rate
+ * callbacks for the pll type clock. Typical calling sequence..
+ *
+ * struct clk *clk = clk_get(NULL, "pll-clk-name");
+ * samsung_pll_clk_set_cb(clk, pll_set_rate, pll_get_rate);
+ */
+void __init samsung_pll_clk_set_cb(struct clk *clk,

drivers/clk/samsung/clk.c line 157

Quoted 10 lines
drivers/clk/samsung/clk.c new file +10 -0
+                       int (*set_rate)(unsigned long rate),
+                       unsigned long (*get_rate)(unsigned long rate))
+{
+       struct samsung_pll_clock *clk_pll;
+       struct clk_hw *hw = __clk_get_hw(clk);
+
+       clk_pll = to_clk_pll(hw);
+       clk_pll->set_rate = set_rate;
+       clk_pll->get_rate = get_rate;
+}

This answers my questions above having different PLL types. Why not just make seprate clk_hw structs for each PLL type instead of the extra layer of abstraction + runtime assignment of clk ops?

Regards,
Mike

#9 lore raw

PATCH v2 1/5 clk: samsung: add common clock framework support for Samsung platforms

Hi Mike,

Thanks for your review.

Quoted 15 lines · Mike Turquette

Hi Thomas,

Quoting Thomas Abraham (2012-10-07 10:10:51)

drivers/clk/samsung/clk.c line 43

Quoted 8 lines
drivers/clk/samsung/clk.c new file +8 -0
+/* determine the output clock speed of the pll */
+static unsigned long samsung_pll_clock_recalc_rate(struct clk_hw *hw,
+                               unsigned long parent_rate)
+{
+       struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
+
+       if (clk_pll->get_rate)
+               return to_clk_pll(hw)->get_rate(parent_rate);

Why the extra indirection? Does your samsung_pll_clock abstract several different PLL implementations (with separate clock ops)? If so, why not make a unique struct for each PLL type?

Yes, it abstracts several PLL types. There are multiple PLL types used by Samsung SoC's and this clock type was supposed to abstract all the types of PLL's. But yes, you are right. It is better to have a unique implementation for each type of PLL. That way, multiple user's of a PLL type need not be worried about setting up runtime callbacks for clock operations.

Quoted 13 lines

drivers/clk/samsung/clk.c line 52

Quoted 10 lines
drivers/clk/samsung/clk.c new file +9 -0
+
+       return 0;
+}
+
+/* round operation not supported */
+static long samsung_pll_clock_round_rate(struct clk_hw *hw, unsigned long drate,
+                               unsigned long *prate)
+{
+       return samsung_pll_clock_recalc_rate(hw, *prate);

Why is round_rate not supported? How is returning the recalculated rate the right thing here?

The PLL does not include a divider for the rounding operation. So the output of the PLL clock type is not something that can be divided down. The parent clock of the PLL clock type is usually a low frequency oscillator. Hence, the round rate operation has not been implemented for the PLL clock type.

Quoted 15 lines
Quoted 15 lines
drivers/clk/samsung/clk.c new file +14 -0
+/*
+ * Allow platform specific implementations to attach set_rate and get_rate
+ * callbacks for the pll type clock. Typical calling sequence..
+ *
+ * struct clk *clk = clk_get(NULL, "pll-clk-name");
+ * samsung_pll_clk_set_cb(clk, pll_set_rate, pll_get_rate);
+ */
+void __init samsung_pll_clk_set_cb(struct clk *clk,
+                       int (*set_rate)(unsigned long rate),
+                       unsigned long (*get_rate)(unsigned long rate))
+{
+       struct samsung_pll_clock *clk_pll;
+       struct clk_hw *hw = __clk_get_hw(clk);
+
Quoted 8 lines

drivers/clk/samsung/clk.c line 157

Quoted 4 lines
drivers/clk/samsung/clk.c new file +4 -0
+       clk_pll = to_clk_pll(hw);
+       clk_pll->set_rate = set_rate;
+       clk_pll->get_rate = get_rate;
+}

This answers my questions above having different PLL types. Why not just make seprate clk_hw structs for each PLL type instead of the extra layer of abstraction + runtime assignment of clk ops?

Ok. I will redo this in the next version of this patch.

Thanks,
Thomas.

Quoted 3 lines

Regards,
Mike

#10 lore raw

PATCH v2 2/5 clk: exynos4: register clocks using common clock framework

In reply to Thomas Abraham

For legacy Exynos4 platforms, the available clocks are statically listed and then registered using the common clock framework. On device tree enabled exynos platfotms, the device tree is searched and all clock nodes found are registered. Support for Exynos4210 and Exynos4x12 platforms is included.

Cc Mike Turquette <[email protected]>
Cc Kukjin Kim <[email protected]>
---
 drivers/clk/samsung/Makefile      |    1 +
 drivers/clk/samsung/clk-exynos4.c |  647 +++++++++++++++++++++++++++++++++++++
 2 files changed, 648 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/Makefile +1 -0
index 3f926b0..69487f7 100644
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_PLAT_SAMSUNG)	+= clk.o
+obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
drivers/clk/samsung/clk-exynos4.c new file +647 -0

647 lines not on this page · raw message

Signature · 1 line
1.7.5.4
#11 lore raw

PATCH v2 2/5 clk: exynos4: register clocks using common clock framework

Hi Thomas,

The whole series looks much better now. Although there is still one more thing from my comments to previous version unresolved, see the inline comment.

Quoted 16 lines · On Monday 08 of October 2012 02:10:52 Thomas Abraham wrote:

For legacy Exynos4 platforms, the available clocks are statically listed and then registered using the common clock framework. On device tree enabled exynos platfotms, the device tree is searched and all clock nodes found are registered. Support for Exynos4210 and Exynos4x12 platforms is included.

Cc Mike Turquette <[email protected]>
Cc Kukjin Kim <[email protected]>
---
 drivers/clk/samsung/Makefile      |    1 +
 drivers/clk/samsung/clk-exynos4.c |  647
+++++++++++++++++++++++++++++++++++++ 2 files changed, 648
insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-exynos4.c

[snip]

drivers/clk/samsung/clk-exynos4.c line 381

Quoted 13 lines
drivers/clk/samsung/clk-exynos4.c new file +13 -0
+			EXYNOS4_CLKSRC_MASK_CAM, 28, "sclk_csis"),
+	GATECLK(NULL, "sclk_cam0", "div_cam0", 0,
+			EXYNOS4_CLKSRC_MASK_CAM, 16, NULL),
+	GATECLK(NULL, "sclk_cam1", "div_cam1", 0,
+			EXYNOS4_CLKSRC_MASK_CAM, 20, NULL),
+	GATECLK("exynos4-fimc.0", "sclk_fimc", "div_fimc0", 0,
+			EXYNOS4_CLKSRC_MASK_CAM, 0, "sclk_fimc"),
+	GATECLK("exynos4-fimc.1", "sclk_fimc", "div_fimc1", 0,
+			EXYNOS4_CLKSRC_MASK_CAM, 4, "sclk_fimc"),
+	GATECLK("exynos4-fimc.2", "sclk_fimc", "div_fimc2", 0,
+			EXYNOS4_CLKSRC_MASK_CAM, 8, "sclk_fimc"),
+	GATECLK("exynos4-fimc.3", "sclk_fimc", "div_fimc3", 0,
+			EXYNOS4_CLKSRC_MASK_CAM, 12, "sclk_fimc"),

You cannot register more than one clock with the same platform name (sclk_fimc). Shouldn't these names be appended with an index, just like with div_fimc{0,1,2,3}?

Best regards,

Signature · 2 lines
Tomasz Figa
Samsung Poland R&D Center
#12 lore raw

PATCH v2 2/5 clk: exynos4: register clocks using common clock framework

In reply to Thomas Abraham
Quoted 16 lines · Thomas Abraham

For legacy Exynos4 platforms, the available clocks are statically listed and then registered using the common clock framework. On device tree enabled exynos platfotms, the device tree is searched and all clock nodes found are registered. Support for Exynos4210 and Exynos4x12 platforms is included.

Cc Mike Turquette <[email protected]>
Cc Kukjin Kim <[email protected]>
---
 drivers/clk/samsung/Makefile      |    1 +
 drivers/clk/samsung/clk-exynos4.c |  647
+++++++++++++++++++++++++++++++++++++
 2 files changed, 648 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-exynos4.c

[...]

drivers/clk/samsung/clk-exynos4.c line 32

Quoted 4 lines
drivers/clk/samsung/clk-exynos4.c new file +4 -0
+
+/* base address of io remapped clock controller register space */
+static	void __iomem *clk_base;
+

I didn't look at the full details. BTW, you know, clock naming is very important and there are some comments about that below...

Quoted 1 line

+static const char *pll_parent_names[] __initdata = { "fin_pll" };

Why is this only 'xxx_parent_names'? not just 'xxx_parents' like others?

Quoted 3 lines
(quoted diff) +2 -0
+static const char *fin_pll_parents[] __initdata = { "xxti", "xusbxti" };
+static const char *mout_apll_parents[] __initdata = { "fin_pll",

"fout_apll", };

According to original naming, how about clk_src_apll here?

+static const char *clk_src_apll[] __initdata = { "fin_pll", "fout_apll", };

Quoted 1 line

+static const char *mout_mpll_parents[] __initdata = { "fin_pll",

clk_src_mpll?

Quoted 2 lines

"fout_mpll", };
+static const char *mout_epll_parents[] __initdata = { "fin_pll",

clk_src_epll?

Review

Quoted 3 lines

"fout_epll", };

(quoted diff) +2 -0
+
+static const char *sclk_ampll_parents[] __initdata = {

clk_src_aclk?

drivers/clk/samsung/clk-exynos4.c line 45

Quoted 9 lines
drivers/clk/samsung/clk-exynos4.c new file +6 -0
+		"mout_mpll", "sclk_apll", };
+
+static const char *sclk_evpll_parents[] __initdata = {
 
 
 
+		"mout_epll", "mout_vpll", };
+
+static const char *mout_core_parents[] __initdata = {

clk_src_core?

Hmm... most of the 'sources' is from out of MUX so mout is not required?...

drivers/clk/samsung/clk-exynos4.c line 49

Quoted 4 lines
drivers/clk/samsung/clk-exynos4.c new file +4 -0
+		"mout_apll", "mout_mpll", };
+
+static const char *mout_mfc_parents[] __initdata = {
+		"mout_mfc0", "mout_mfc1", };

Should be following?

+static const char *clk_src_mfc0[] __initdata = {"mout_mpll", "sclk_apll", };
+static const char *clk_src_mfc1[] __initdata = {"mout_epll", "sclk_vpll", };

drivers/clk/samsung/clk-exynos4.c line 52

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+
+static const char *mout_dac_parents[] __initdata = {
+		"mout_vpll", "sclk_hdmiphy", };

sclk_vpll?

+static const char *clk_src_sclk_dac[] __initdata = {"sclk_vpll", "sclk_hdmiphy", };

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+static const char *mout_hdmi_parents[] __initdata = {

clk_src_sclk_hdmi?

drivers/clk/samsung/clk-exynos4.c line 57

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+		"sclk_pixel", "sclk_hdmiphy", };
+
+static const char *mout_mixer_parents[] __initdata = {

clk_src_sclk_mixer?

drivers/clk/samsung/clk-exynos4.c line 60

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+		"sclk_dac", "sclk_hdmi", };
+
+static const char *group1_parents[] __initdata = {

According to original clock-exynos4.c, just 'group_parents' not 'group1_parents'?

drivers/clk/samsung/clk-exynos4.c line 61

Quoted 1 line
drivers/clk/samsung/clk-exynos4.c new file +1 -0
+		"xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0",

Should be 'sclk_hdmi27m' instead of 'sclk_hdmi24m'
+ "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0",

drivers/clk/samsung/clk-exynos4.c line 62

Quoted 1 line
drivers/clk/samsung/clk-exynos4.c new file +1 -0
+		"none", "sclk_hdmiphy", "mout_mpll", "mout_epll",

Missed 'sclk_usbphy1'?
+ "sclk_usbphy1", "sclk_hdmiphy", "mout_mpll", "mout_epll",

drivers/clk/samsung/clk-exynos4.c line 67

Quoted 5 lines
drivers/clk/samsung/clk-exynos4.c new file +5 -0
+		"mout_vpll" };
+
+static struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] = {
+	FRATE_CLK(NULL, "xxti", NULL, CLK_IS_ROOT, 24000000),
+	FRATE_CLK(NULL, "xusbxti", NULL, CLK_IS_ROOT, 24000000),

Well, above clock rate depends on board and it means it is not a fixed value.

drivers/clk/samsung/clk-exynos4.c line 70

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+	FRATE_CLK(NULL, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000),
+	FRATE_CLK(NULL, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
+	FRATE_CLK(NULL, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000),

Missed sclk_hdmi27m?
+ FRATE_CLK(NULL, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000),

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+};
+
+static struct samsung_mux_clock exynos4_mux_clks[] = {

[...]

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+};
+
+static struct samsung_div_clock exynos4_div_clks[] = {

[...]

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+};
+
+struct samsung_gate_clock exynos4_gate_clks[] = {

[...]

drivers/clk/samsung/clk-exynos4.c line 532

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	clk = clk_get(NULL, "fout_apll");
+	samsung_pll_clk_set_cb(clk, NULL, exynos4210_get_rate_apll);

+ samsung_pll_clk_set_cb(clk, NULL, exynos4210_apll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 533

Quoted 1 line
drivers/clk/samsung/clk-exynos4.c new file +1 -0
+	clk = clk_get(NULL, "fout_mpll");

+ samsung_pll_clk_set_cb(clk, NULL, exynos4210_mpll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 536

Quoted 5 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+	samsung_pll_clk_set_cb(clk, NULL, exynos4210_get_rate_mpll);
 
 
+	clk = clk_get(NULL, "fout_epll");
+	samsung_pll_clk_set_cb(clk, NULL, exynos4210_get_rate_epll);

+ samsung_pll_clk_set_cb(clk, NULL, exynos4210_epll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 539

Quoted 3 lines
drivers/clk/samsung/clk-exynos4.c new file +3 -0
+	clk = clk_get(NULL, "fout_vpll");
+	samsung_pll_clk_set_cb(clk, exynos4210_vpll_set_rate,
+				exynos4210_get_rate_mpll);

mpll? Should be vpll?

+ exynos4210_vpll_get_rate); ???

[...]

drivers/clk/samsung/clk-exynos4.c line 561

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_apll", pll_parent_names, NULL,
+		NULL, exynos4210_get_rate_apll);

+ NULL, exynos4210_apll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 563

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_mpll", pll_parent_names, NULL,
+		NULL, exynos4210_get_rate_mpll);

+ NULL, exynos4210_mpll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 565

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_epll", pll_parent_names, NULL,
+		NULL, exynos4210_get_rate_epll);

+ NULL, exynos4210_epll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 567

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_vpll", exynos4210_vpll_parent_names,
+		NULL, exynos4210_vpll_set_rate, exynos4210_get_rate_vpll);

+ NULL, exynos4210_vpll_set_rate, exynos4210_vpll_get_rate);

[...]

Quoted 1 line

+static unsigned long exynos4x12_get_rate_apll(unsigned long xtal_rate)

exynos4x12_apll_get_rate()

drivers/clk/samsung/clk-exynos4.c line 605

Quoted 5 lines
drivers/clk/samsung/clk-exynos4.c new file +5 -0
+{
+	return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0));
+}
+
+static unsigned long exynos4x12_get_rate_mpll(unsigned long xtal_rate)

exynos4x12_mpll_get_rate()

drivers/clk/samsung/clk-exynos4.c line 610

Quoted 5 lines
drivers/clk/samsung/clk-exynos4.c new file +5 -0
+{
+	return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_MPLL_CON0));
+}
+
+static unsigned long exynos4x12_get_rate_epll(unsigned long xtal_rate)

exynos4x12_epll_get_rate()

drivers/clk/samsung/clk-exynos4.c line 616

Quoted 6 lines
drivers/clk/samsung/clk-exynos4.c new file +6 -0
+{
+	return s5p_get_pll36xx(xtal_rate, __raw_readl(EXYNOS4_EPLL_CON0),
+		__raw_readl(EXYNOS4_EPLL_CON1));
+}
+
+static unsigned long exynos4x12_get_rate_vpll(unsigned long vpllsrc_rate)

exynos4x12_vpll_get_rate()

drivers/clk/samsung/clk-exynos4.c line 628

Quoted 12 lines
drivers/clk/samsung/clk-exynos4.c new file +12 -0
+{
+	return s5p_get_pll36xx(vpllsrc_rate, __raw_readl(EXYNOS4_VPLL_CON0),
+		__raw_readl(EXYNOS4_VPLL_CON1));
+}
+
+/* Exynos4x12 specific clock registeration */
+void __init exynos4x12_clk_init(void)
+{
+	exynos4_clk_init();
+
+	samsung_clk_register_pll("fout_apll", pll_parent_names, NULL,
+		NULL, exynos4x12_get_rate_apll);

+ NULL, exynos4x12_apll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 630

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_mpll", pll_parent_names, NULL,
+		NULL, exynos4x12_get_rate_mpll);

+ NULL, exynos4x12_mpll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 632

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_epll", pll_parent_names, NULL,
+		NULL, exynos4x12_get_rate_epll);

+ NULL, exynos4x12_epll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 634

Quoted 2 lines
drivers/clk/samsung/clk-exynos4.c new file +2 -0
+	samsung_clk_register_pll("fout_vpll", pll_parent_names, NULL,
+		NULL, exynos4x12_get_rate_vpll);

+ NULL, exynos4x12_vpll_get_rate);

drivers/clk/samsung/clk-exynos4.c line 639

Quoted 5 lines
drivers/clk/samsung/clk-exynos4.c new file +5 -0
+
+	samsung_clk_register_mux(exynos4x12_mux_clks,
+			ARRAY_SIZE(exynos4x12_mux_clks));
+
+	pr_info("EXYNOS4210: PLL settings: A=%ld, M=%ld, E=%ld, V=%ld\n",

pr_info("EXYNOS4X12:...

drivers/clk/samsung/clk-exynos4.c line 579

Quoted 4 lines
drivers/clk/samsung/clk-exynos4.c new file +4 -0
+		_get_rate("fout_apll"), _get_rate("fout_mpll"),
+		_get_rate("fout_epll"), _get_rate("fout_vpll"));
+
+	pr_info("EXYNOS4210: ARMCLK=%ld, ACLK200=%ld, ACLK100=%ld\n"

pr_info("EXYNOS4X12:...

Quoted 6 lines
drivers/clk/samsung/clk-exynos4.c new file +4 -1
+		"         ACLK160=%ld, ACLK133=%ld\n", _get_rate("armclk"),
+		_get_rate("aclk_200"), _get_rate("aclk_100"),
+		_get_rate("aclk_160"), _get_rate("aclk_133"));
+}
--

1.7.5.4

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#13 lore raw

PATCH v2 3/5 ARM: dts: Add Exynos4210 clock nodes

In reply to Thomas Abraham

Add initial set of Exynos4210 clock nodes with which device tree enabled boards based on Exynos4210 can be booted.

---
 arch/arm/boot/dts/exynos4-clock.dtsi |  389 ++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/exynos4.dtsi       |    1 +
 2 files changed, 390 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/exynos4-clock.dtsi
arch/arm/boot/dts/exynos4-clock.dtsi new file +389 -0
new file mode 100644
index 0000000..eb07613
@@ -0,0 +1,389 @@
+/*
+ * Samsung's Exynos4210 SoC clock nodes
+ *
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ * Copyright (c) 2011-2012 Linaro Ltd.
+ *		www.linaro.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/ {
+	clock_ctrl at 10030000 {
+		compatible = "samsung,exynos4-clock-ctrl";
+		reg = <0x10030000 0x20000>;
+
+		xxti: xxti {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "xxti";
+			clock-frequency = <24000000>;
+		};
+
+		xusbxti: xusbxti {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "xusbxti";
+			clock-frequency = <24000000>;
+		};
+
+		sclk_hdmi24m: sclk_hdmi24m {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_hdmi24m";
+			clock-frequency = <24000000>;
+		};
+
+		sclk_hdmiphy: sclk_hdmiphy {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_hdmiphy";
+			clock-frequency = <27000000>;
+		};
+
+		sclk_usbphy0: sclk_usbphy0 {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_usbphy0";
+			clock-frequency = <48000000>;
+		};
+
+		sclk_usbphy1: sclk_usbphy1 {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_usbphy1";
+			clock-frequency = <48000000>;
+		};
+
+		fin_pll: fin_pll {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "fin_pll";
+			clocks = <&xxti>, <&xusbxti>;
+			reg-info = <0x00 0 1>;
+		};
+
+		fout_apll: fout_apll {
+			compatible = "samsung,clock-pll";
+			#clock-cells = <0>;
+			clock-output-names = "fout_apll";
+			clocks = <&fin_pll>;
+		};
+
+		fout_mpll: fout_mpll {
+			compatible = "samsung,clock-pll";
+			#clock-cells = <0>;
+			clock-output-names = "fout_mpll";
+			clocks = <&fin_pll>;
+		};
+
+		fout_epll: fout_epll {
+			compatible = "samsung,clock-pll";
+			#clock-cells = <0>;
+			clock-output-names = "fout_epll";
+			clocks = <&fin_pll>;
+		};
+
+		mout_epll: mout_epll {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_epll";
+			clocks = <&fin_pll>, <&fout_epll>;
+			reg-info = <0xc210 8 1>;
+		};
+
+		mout_vpll_src: mout_vpll_src {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_vpll_src";
+			clocks = <&fin_pll>, <&sclk_hdmi24m>;
+			reg-info = <0xc214 0 1>;
+		};
+
+		fout_vpll: fout_vpll {
+			compatible = "samsung,clock-pll";
+			#clock-cells = <0>;
+			clock-output-names = "fout_vpll";
+			clocks = <&mout_vpll_src>;
+		};
+
+		mout_vpll: mout_vpll {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_vpll";
+			clocks = <&mout_vpll_src>, <&fout_vpll>;
+			reg-info = <0xc210 8 1>;
+		};
+
+		mout_apll: mout_apll {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_apll";
+			clocks = <&fin_pll>, <&fout_apll>;
+			reg-info = <0x14200 0 1>;
+		};
+
+		mout_mpll: mout_mpll {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_mpll";
+			clocks = <&fin_pll>, <&fout_mpll>;
+			reg-info = <0x14200 8 1>;
+		};
+
+		sclk_apll: sclk_apll {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_apll";
+			clocks = <&mout_apll>;
+			reg-info = <0x14500 24 3>;
+		};
+
+		mout_core: mout_core {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_core";
+			clocks = <&mout_apll>, <&mout_mpll>;
+			reg-info = <0x14200 16 1>;
+		};
+
+		div_core: div_core {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "div_core";
+			clocks = <&mout_core>;
+			reg-info = <0x14500 0 3>;
+		};
+
+		armclk: armclk {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "armclk";
+			clocks = <&div_core>;
+			reg-info = <0x14500 28 3>;
+		};
+
+		mout_aclk_200: mout_aclk_200 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_aclk_200";
+			clocks = <&mout_mpll>, <&sclk_apll>;
+			reg-info = <0xc210 12 1>;
+		};
+
+		mout_aclk_100: mout_aclk_100 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_aclk_100";
+			clocks = <&mout_mpll>, <&sclk_apll>;
+			reg-info = <0xc210 16 1>;
+		};
+
+		mout_aclk_160: mout_aclk_160 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_aclk_160";
+			clocks = <&mout_mpll>, <&sclk_apll>;
+			reg-info = <0xc210 20 1>;
+		};
+
+		mout_aclk_133: mout_aclk_133 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_aclk_133";
+			clocks = <&mout_mpll>, <&sclk_apll>;
+			reg-info = <0xc210 24 1>;
+		};
+
+		aclk_200: aclk_200 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "aclk_200";
+			clocks = <&mout_aclk_200>;
+			reg-info = <0xc510 0 3>;
+		};
+
+		aclk_100: aclk_100 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "aclk_100";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc510 4 3>;
+		};
+
+		aclk_160: aclk_160 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "aclk_160";
+			clocks = <&mout_aclk_160>;
+			reg-info = <0xc510 8 3>;
+		};
+
+		aclk_133: aclk_133 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "aclk_133";
+			clocks = <&mout_aclk_133>;
+			reg-info = <0xc510 12 3>;
+		};
+
+		uart0: uart0 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "uart0";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc94c 0>;
+		};
+
+		uart1: uart1 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "uart1";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc94c 1>;
+		};
+
+		uart2: uart2 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "uart2";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc94c 2>;
+		};
+
+		uart3: uart3 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "uart3";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc94c 3>;
+		};
+
+		uart4: uart4 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "uart4";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc94c 4>;
+		};
+
+		uart5: uart5 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "uart5";
+			clocks = <&mout_aclk_100>;
+			reg-info = <0xc94c 5>;
+		};
+
+		mout_uart0: mout_uart0 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_uart0";
+			clocks = <&xxti>, <&xusbxti>, <&sclk_hdmi24m>,
+				 <&sclk_usbphy0>, <&sclk_usbphy1>,
+				 <&sclk_hdmiphy>, <&mout_mpll>, <&mout_epll>,
+				 <&mout_vpll>;
+			reg-info = <0xc250 0 4>;
+		};
+
+		mout_uart1: mout_uart1 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_uart1";
+			clocks = <&xxti>, <&xusbxti>, <&sclk_hdmi24m>,
+				 <&sclk_usbphy0>, <&sclk_usbphy1>,
+				 <&sclk_hdmiphy>, <&mout_mpll>, <&mout_epll>,
+				 <&mout_vpll>;
+			reg-info = <0xc250 4 4>;
+		};
+
+		mout_uart2: mout_uart2 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_uart2";
+			clocks = <&xxti>, <&xusbxti>, <&sclk_hdmi24m>,
+				 <&sclk_usbphy0>, <&sclk_usbphy1>,
+				 <&sclk_hdmiphy>, <&mout_mpll>, <&mout_epll>,
+				 <&mout_vpll>;
+			reg-info = <0xc250 8 4>;
+		};
+
+		mout_uart3: mout_uart3 {
+			compatible = "samsung,clock-mux";
+			#clock-cells = <0>;
+			clock-output-names = "mout_uart3";
+			clocks = <&xxti>, <&xusbxti>, <&sclk_hdmi24m>,
+				 <&sclk_usbphy0>, <&sclk_usbphy1>,
+				 <&sclk_hdmiphy>, <&mout_mpll>, <&mout_epll>,
+				 <&mout_vpll>;
+			reg-info = <0xc250 12 4>;
+		};
+
+		dout_uart0: dout_uart0 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "dout_uart0";
+			clocks = <&mout_uart0>;
+			reg-info = <0xc550 0 4>;
+		};
+
+		dout_uart1: dout_uart1 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "dout_uart1";
+			clocks = <&mout_uart1>;
+			reg-info = <0xc550 4 4>;
+		};
+
+		dout_uart2: dout_uart2 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "dout_uart2";
+			clocks = <&mout_uart2>;
+			reg-info = <0xc550 8 4>;
+		};
+
+		dout_uart3: dout_uart3 {
+			compatible = "samsung,clock-div";
+			#clock-cells = <0>;
+			clock-output-names = "dout_uart3";
+			clocks = <&mout_uart3>;
+			reg-info = <0xc550 12 4>;
+		};
+
+		sclk_uart0: sclk_uart0 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_uart0";
+			clocks = <&dout_uart0>;
+			reg-info = <0xc350 0>;
+		};
+
+		sclk_uart1: sclk_uart1 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_uart1";
+			clocks = <&dout_uart1>;
+			reg-info = <0xc350 4>;
+		};
+
+		sclk_uart2: sclk_uart2 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_uart2";
+			clocks = <&dout_uart2>;
+			reg-info = <0xc350 8>;
+		};
+
+		sclk_uart3: sclk_uart3 {
+			compatible = "samsung,clock-gate";
+			#clock-cells = <0>;
+			clock-output-names = "sclk_uart3";
+			clocks = <&dout_uart3>;
+			reg-info = <0xc350 12>;
+		};
+	};
+};
arch/arm/boot/dts/exynos4.dtsi +1 -0
index a26c3dd..1c923d3 100644
@@ -20,6 +20,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "exynos4-clock.dtsi"
 
 / {
 	interrupt-parent = <&gic>;
Signature · 1 line
1.7.5.4
#14 lore raw

PATCH v2 4/5 ARM: dts: list the clock providers for serial ports

In reply to Thomas Abraham

Add the list of clock providers in the serial port device nodes.

---
 arch/arm/boot/dts/exynos4.dtsi |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
arch/arm/boot/dts/exynos4.dtsi +8 -0
index 1c923d3..eb1cdda 100644
@@ -98,6 +98,8 @@
 		compatible = "samsung,exynos4210-uart";
 		reg = <0x13800000 0x100>;
 		interrupts = <0 52 0>;
+		clocks = <&uart0>, <&sclk_uart0>;
+		clock-names = "uart", "clk_uart_baud0";
 		status = "disabled";
 	};
 
@@ -105,6 +107,8 @@
 		compatible = "samsung,exynos4210-uart";
 		reg = <0x13810000 0x100>;
 		interrupts = <0 53 0>;
+		clocks = <&uart1>, <&sclk_uart1>;
+		clock-names = "uart", "clk_uart_baud0";
 		status = "disabled";
 	};
 
@@ -112,6 +116,8 @@
 		compatible = "samsung,exynos4210-uart";
 		reg = <0x13820000 0x100>;
 		interrupts = <0 54 0>;
+		clocks = <&uart2>, <&sclk_uart2>;
+		clock-names = "uart", "clk_uart_baud0";
 		status = "disabled";
 	};
 
@@ -119,6 +125,8 @@
 		compatible = "samsung,exynos4210-uart";
 		reg = <0x13830000 0x100>;
 		interrupts = <0 55 0>;
+		clocks = <&uart3>, <&sclk_uart3>;
+		clock-names = "uart", "clk_uart_baud0";
 		status = "disabled";
 	};
 
Signature · 1 line
1.7.5.4
#15 lore raw

PATCH v2 5/5 ARM: Exynos4: Migrate clock support to common clock framework

In reply to Thomas Abraham

Remove Samsung specific clock support in Exynos4 and migrate to using common clock framework.

---
 arch/arm/mach-exynos/Kconfig               |    1 +
 arch/arm/mach-exynos/Makefile              |    3 -
 arch/arm/mach-exynos/clock-exynos4.c       | 1603 ----------------------------
 arch/arm/mach-exynos/clock-exynos4.h       |   35 -
 arch/arm/mach-exynos/clock-exynos4210.c    |  188 ----
 arch/arm/mach-exynos/clock-exynos4212.c    |  192 ----
 arch/arm/mach-exynos/common.c              |   22 +-
 arch/arm/mach-exynos/common.h              |    3 +
 arch/arm/mach-exynos/mach-armlex4210.c     |    1 -
 arch/arm/mach-exynos/mach-exynos4-dt.c     |    1 -
 arch/arm/mach-exynos/mach-nuri.c           |    1 -
 arch/arm/mach-exynos/mach-origen.c         |    1 -
 arch/arm/mach-exynos/mach-smdk4x12.c       |    1 -
 arch/arm/mach-exynos/mach-smdkv310.c       |    1 -
 arch/arm/mach-exynos/mach-universal_c210.c |    1 -
 arch/arm/mach-exynos/mct.c                 |   11 +-
 arch/arm/plat-samsung/Kconfig              |    4 +-
 17 files changed, 18 insertions(+), 2051 deletions(-)
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4.h
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4210.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4212.c
arch/arm/mach-exynos/Kconfig +1 -0
index 4372075..3c80eba 100644
@@ -15,6 +15,7 @@ config ARCH_EXYNOS4
 	bool "SAMSUNG EXYNOS4"
 	default y
 	select HAVE_SMP
+	select COMMON_CLK
 	select MIGHT_HAVE_CACHE_L2X0
 	help
 	  Samsung EXYNOS4 SoCs based systems
arch/arm/mach-exynos/Makefile +0 -3
index 9b58024..ad66c9f4 100644
@@ -13,10 +13,7 @@ obj-				:=
 # Core
 
 obj-$(CONFIG_ARCH_EXYNOS)	+= common.o
-obj-$(CONFIG_ARCH_EXYNOS4)	+= clock-exynos4.o
 obj-$(CONFIG_ARCH_EXYNOS5)	+= clock-exynos5.o
-obj-$(CONFIG_CPU_EXYNOS4210)	+= clock-exynos4210.o
-obj-$(CONFIG_SOC_EXYNOS4212)	+= clock-exynos4212.o
 
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
arch/arm/mach-exynos/clock-exynos4.c deleted +0 -1603

1,603 lines not on this page · raw message

arch/arm/mach-exynos/clock-exynos4.h deleted +0 -35
deleted file mode 100644
index bd12d5f..0000000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Header file for exynos4 clock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_CLOCK_H
-#define __ASM_ARCH_CLOCK_H __FILE__
-
-#include <linux/clk.h>
-
-extern struct clksrc_clk exynos4_clk_aclk_133;
-extern struct clksrc_clk exynos4_clk_mout_mpll;
-
-extern struct clksrc_sources exynos4_clkset_mout_corebus;
-extern struct clksrc_sources exynos4_clkset_group;
-
-extern struct clk *exynos4_clkset_aclk_top_list[];
-extern struct clk *exynos4_clkset_group_list[];
-
-extern struct clksrc_sources exynos4_clkset_mout_g2d0;
-extern struct clksrc_sources exynos4_clkset_mout_g2d1;
-
-extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable);
-extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable);
-extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable);
-extern int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable);
-extern int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable);
-
-#endif /* __ASM_ARCH_CLOCK_H */
arch/arm/mach-exynos/clock-exynos4210.c deleted +0 -188

188 lines not on this page · raw message

arch/arm/mach-exynos/clock-exynos4212.c deleted +0 -192

192 lines not on this page · raw message

arch/arm/mach-exynos/common.c +2 -20
index 715b690..fea1542 100644
@@ -60,7 +60,6 @@ static const char name_exynos5250[] = "EXYNOS5250";
 
 static void exynos4_map_io(void);
 static void exynos5_map_io(void);
-static void exynos4_init_clocks(int xtal);
 static void exynos5_init_clocks(int xtal);
 static void exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 static int exynos_init(void);
@@ -70,7 +69,6 @@ static struct cpu_table cpu_ids[] __initdata = {
 		.idcode		= EXYNOS4210_CPU_ID,
 		.idmask		= EXYNOS4_CPU_MASK,
 		.map_io		= exynos4_map_io,
-		.init_clocks	= exynos4_init_clocks,
 		.init_uarts	= exynos_init_uarts,
 		.init		= exynos_init,
 		.name		= name_exynos4210,
@@ -78,7 +76,6 @@ static struct cpu_table cpu_ids[] __initdata = {
 		.idcode		= EXYNOS4212_CPU_ID,
 		.idmask		= EXYNOS4_CPU_MASK,
 		.map_io		= exynos4_map_io,
-		.init_clocks	= exynos4_init_clocks,
 		.init_uarts	= exynos_init_uarts,
 		.init		= exynos_init,
 		.name		= name_exynos4212,
@@ -86,7 +83,6 @@ static struct cpu_table cpu_ids[] __initdata = {
 		.idcode		= EXYNOS4412_CPU_ID,
 		.idmask		= EXYNOS4_CPU_MASK,
 		.map_io		= exynos4_map_io,
-		.init_clocks	= exynos4_init_clocks,
 		.init_uarts	= exynos_init_uarts,
 		.init		= exynos_init,
 		.name		= name_exynos4412,
@@ -368,31 +364,17 @@ static void __init exynos5_map_io(void)
 	s3c_i2c2_setname("s3c2440-i2c");
 }
 
-static void __init exynos4_init_clocks(int xtal)
-{
-	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
-
-	s3c24xx_register_baseclocks(xtal);
-	s5p_register_clocks(xtal);
-
-	if (soc_is_exynos4210())
-		exynos4210_register_clocks();
-	else if (soc_is_exynos4212() || soc_is_exynos4412())
-		exynos4212_register_clocks();
-
-	exynos4_register_clocks();
-	exynos4_setup_clocks();
-}
-
 static void __init exynos5_init_clocks(int xtal)
 {
 	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
 
+#ifndef CONFIG_COMMON_CLK
 	s3c24xx_register_baseclocks(xtal);
 	s5p_register_clocks(xtal);
 
 	exynos5_register_clocks();
 	exynos5_setup_clocks();
+#endif
 }
 
 #define COMBINER_ENABLE_SET	0x0
arch/arm/mach-exynos/common.h +3 -0
index dac146d..7a4e0ea 100644
@@ -22,6 +22,9 @@ void exynos4_restart(char mode, const char *cmd);
 void exynos5_restart(char mode, const char *cmd);
 void exynos_init_late(void);
 
+void exynos4210_clk_init(void);
+void exynos4x12_clk_init(void);
+
 #ifdef CONFIG_PM_GENERIC_DOMAINS
 int exynos_pm_late_initcall(void);
 #else
arch/arm/mach-exynos/mach-armlex4210.c +0 -1
index 3f37a5e..583c6a7 100644
@@ -179,7 +179,6 @@ static void __init armlex4210_smsc911x_init(void)
 static void __init armlex4210_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(24000000);
 	s3c24xx_init_uarts(armlex4210_uartcfgs,
 			   ARRAY_SIZE(armlex4210_uartcfgs));
 }
arch/arm/mach-exynos/mach-exynos4-dt.c +0 -1
index e58d786..8f6687b 100644
@@ -83,7 +83,6 @@ static const struct of_dev_auxdata exynos4_auxdata_lookup[] __initconst = {
 static void __init exynos4_dt_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(24000000);
 }
 
 static void __init exynos4_dt_machine_init(void)
arch/arm/mach-exynos/mach-nuri.c +0 -1
index 480cd78f..9b7aa9d 100644
@@ -1338,7 +1338,6 @@ static struct platform_device *nuri_devices[] __initdata = {
 static void __init nuri_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(clk_xusbxti.rate);
 	s3c24xx_init_uarts(nuri_uartcfgs, ARRAY_SIZE(nuri_uartcfgs));
 }
 
arch/arm/mach-exynos/mach-origen.c +0 -1
index 67b50bb..0d6b877 100644
@@ -756,7 +756,6 @@ static void s5p_tv_setup(void)
 static void __init origen_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(clk_xusbxti.rate);
 	s3c24xx_init_uarts(origen_uartcfgs, ARRAY_SIZE(origen_uartcfgs));
 }
 
arch/arm/mach-exynos/mach-smdk4x12.c +0 -1
index 7a265d1..d1a7668 100644
@@ -326,7 +326,6 @@ static struct platform_device *smdk4x12_devices[] __initdata = {
 static void __init smdk4x12_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(clk_xusbxti.rate);
 	s3c24xx_init_uarts(smdk4x12_uartcfgs, ARRAY_SIZE(smdk4x12_uartcfgs));
 }
 
arch/arm/mach-exynos/mach-smdkv310.c +0 -1
index c15d223..ead65a2 100644
@@ -376,7 +376,6 @@ static void s5p_tv_setup(void)
 static void __init smdkv310_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(clk_xusbxti.rate);
 	s3c24xx_init_uarts(smdkv310_uartcfgs, ARRAY_SIZE(smdkv310_uartcfgs));
 }
 
arch/arm/mach-exynos/mach-universal_c210.c +0 -1
index 98d3ace..bd4d1f0 100644
@@ -1100,7 +1100,6 @@ static struct platform_device *universal_devices[] __initdata = {
 static void __init universal_map_io(void)
 {
 	exynos_init_io(NULL, 0);
-	s3c24xx_init_clocks(clk_xusbxti.rate);
 	s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs));
 	s5p_set_timer_source(S5P_PWM2, S5P_PWM4);
 }
arch/arm/mach-exynos/mct.c +10 -1
index b601fb8..cc3805a 100644
@@ -30,6 +30,8 @@
 #include <mach/regs-mct.h>
 #include <asm/mach/time.h>
 
+#include "common.h"
+
 #define TICK_BASE_CNT	1
 
 enum {
@@ -457,7 +459,7 @@ static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
 static void __init exynos4_timer_resources(void)
 {
 	struct clk *mct_clk;
-	mct_clk = clk_get(NULL, "xtal");
+	mct_clk = clk_get(NULL, "fin_pll");
 
 	clk_rate = clk_get_rate(mct_clk);
 
@@ -478,6 +480,13 @@ static void __init exynos4_timer_resources(void)
 
 static void __init exynos4_timer_init(void)
 {
+#ifdef CONFIG_COMMON_CLK
+	if (soc_is_exynos4210())
+		exynos4210_clk_init();
+	else if (soc_is_exynos4212() || soc_is_exynos4412())
+		exynos4x12_clk_init();
+#endif
+
 	if ((soc_is_exynos4210()) || (soc_is_exynos5250()))
 		mct_int_type = MCT_INT_SPI;
 	else
arch/arm/plat-samsung/Kconfig +2 -2
index 9c3b90c..35b4cb8 100644
@@ -26,7 +26,7 @@ config PLAT_S5P
 	select S5P_GPIO_DRVSTR
 	select SAMSUNG_GPIOLIB_4BIT
 	select PLAT_SAMSUNG
-	select SAMSUNG_CLKSRC
+	select SAMSUNG_CLKSRC if !COMMON_CLK
 	select SAMSUNG_IRQ_VIC_TIMER
 	help
 	  Base platform code for Samsung's S5P series SoC.
@@ -89,7 +89,7 @@ config SAMSUNG_CLKSRC
 	  used by newer systems such as the S3C64XX.
 
 config S5P_CLOCK
-	def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
+	def_bool ((ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) && !COMMON_CLK)
 	help
 	  Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs
 
Signature · 1 line
1.7.5.4
#16 lore raw

PATCH v2 5/5 ARM: Exynos4: Migrate clock support to common clock framework

Quoted 10 lines · Thomas Abraham

Remove Samsung specific clock support in Exynos4 and migrate to using common clock framework.

---
 arch/arm/mach-exynos/Kconfig               |    1 +
 arch/arm/mach-exynos/Makefile              |    3 -
 arch/arm/mach-exynos/clock-exynos4.c       | 1603

-------------------------

Quoted 12 lines
---
 arch/arm/mach-exynos/clock-exynos4.h       |   35 -
 arch/arm/mach-exynos/clock-exynos4210.c    |  188 ----
 arch/arm/mach-exynos/clock-exynos4212.c    |  192 ----
 arch/arm/mach-exynos/common.c              |   22 +-
 arch/arm/mach-exynos/common.h              |    3 +
 arch/arm/mach-exynos/mach-armlex4210.c     |    1 -
 arch/arm/mach-exynos/mach-exynos4-dt.c     |    1 -
 arch/arm/mach-exynos/mach-nuri.c           |    1 -
 arch/arm/mach-exynos/mach-origen.c         |    1 -
 arch/arm/mach-exynos/mach-smdk4x12.c       |    1 -
 arch/arm/mach-exynos/mach-smdkv310.c       |    1 -
Quoted 8 lines
 arch/arm/mach-exynos/mach-universal_c210.c |    1 -
 arch/arm/mach-exynos/mct.c                 |   11 +-
 arch/arm/plat-samsung/Kconfig              |    4 +-
 17 files changed, 18 insertions(+), 2051 deletions(-)
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4.h
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4210.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4212.c

I think, would be better to us if we could keep this clock stuff with common clock for a moment, e.g. 3.8. In addition, the clock stuff is still updating at this moment so we need some time to move on common clock framework entirely. Of course, I have no objection to support common clock on new SoC such as exynos5440 :-)

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#17 lore raw

PATCH v2 5/5 ARM: Exynos4: Migrate clock support to common clock framework

In reply to Thomas Abraham
Quoted 11 lines · Kukjin Kim
Quoted 10 lines · Thomas Abraham

Remove Samsung specific clock support in Exynos4 and migrate to using common clock framework.

---
 arch/arm/mach-exynos/Kconfig               |    1 +
 arch/arm/mach-exynos/Makefile              |    3 -
 arch/arm/mach-exynos/clock-exynos4.c       | 1603

-----------------------

Quoted 22 lines

--

Quoted 12 lines
---
 arch/arm/mach-exynos/clock-exynos4.h       |   35 -
 arch/arm/mach-exynos/clock-exynos4210.c    |  188 ----
 arch/arm/mach-exynos/clock-exynos4212.c    |  192 ----
 arch/arm/mach-exynos/common.c              |   22 +-
 arch/arm/mach-exynos/common.h              |    3 +
 arch/arm/mach-exynos/mach-armlex4210.c     |    1 -
 arch/arm/mach-exynos/mach-exynos4-dt.c     |    1 -
 arch/arm/mach-exynos/mach-nuri.c           |    1 -
 arch/arm/mach-exynos/mach-origen.c         |    1 -
 arch/arm/mach-exynos/mach-smdk4x12.c       |    1 -
 arch/arm/mach-exynos/mach-smdkv310.c       |    1 -
Quoted 8 lines
 arch/arm/mach-exynos/mach-universal_c210.c |    1 -
 arch/arm/mach-exynos/mct.c                 |   11 +-
 arch/arm/plat-samsung/Kconfig              |    4 +-
 17 files changed, 18 insertions(+), 2051 deletions(-)  delete mode
100644 arch/arm/mach-exynos/clock-exynos4.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4.h
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4210.c
 delete mode 100644 arch/arm/mach-exynos/clock-exynos4212.c
Quoted 6 lines

I think, would be better to us if we could keep this clock stuff with common clock for a moment, e.g. 3.8. In addition, the clock stuff is still updating at this moment so we need some time to move on common clock framework entirely. Of course, I have no objection to support common clock on new SoC such as exynos5440 :-)

Oops, I'm resending because of e-mail client problem.

Quoted 7 lines

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.