linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms
@ 2014-01-18 12:10 Thomas Abraham
  2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
                   ` (6 more replies)
  0 siblings, 7 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

Changes since v1:
- Removes Exynos4x12 and Exynos5250 cpufreq driver also.
- Device tree based clock configuration lookup as suggested by Lukasz
  Majewski and Tomasz Figa.
- safe operating point binding reworked as suggested by Shawn Guo.

The patch series removes the use of Exynos specific cpufreq driver and enables
the use of cpufreq-cpu0 driver for Exynos4210, Exynos4x12 and Exynos5250 based
platforms. This is being done for few reasons.

(a) The Exynos cpufreq driver reads/writes clock controller registers
    bypassing the Exynos CCF driver which is sort of problematic.
(b) Removes the need for having clock controller register definitions
    in the cpufreq driver and also removes the need for statically
    io-remapping clock controller address space (helps in moving towards
    multiplatform kernel).

In order to use cpufreq-cpu0 driver and provide fast cpu clock switching
during dvfs operations, the following apporach has been used.

(a) A new CPU clock provider type has been introduced in Samsung's CCF
    support. This clock provider type can be a compostion of multiple
    clock blocks such as mux, dividers and gates. Typically, in Exynos
    platforms, there are multiple clock blocks in between the output
    of the APLL and the CPU clock domain output. Representing these
    mutiple clock blocks within a opaque CPU clock provider type helps
    in reducing the time taken to perform a CPU clock frequency change
    operation, which is generally required during DVFS operations.
    This approach was suggested by Arnd Bergmann <arnd@arndb.de> during
    LCE-2013.

(b) A new optional safe operating point property has been introduced
    in the cpufreq-cpu0 driver binding. On some platforms such as the
    Samsung Exynos, a change in CPU frequency requires a change in the
    PLL output that drives the CPU clock. A change in PLL output
    requires the PLL output be turned off, which implies that the CPU
    (and other components in the CPU clock domain) be supplied with
    an alternate clock source during the time the PLL output is changed.

    The clock speed of this alternate clock source could be higher
    than the clock speed of the PLL at the time of switching over to
    the alternate clock source. This temporary increase in clock speed
    of the CPU clock domain implies that the blocks within the CPU
    clock domain should also be supplied with an appropriate voltage
    supply level as required to drive the CPU clock domain components
    at the speed of the alternative clock source. This temporary
    voltage level required during switching of CPU clock speed is
    called safe voltage level. And the cpufreq-cpu0 driver has been
    modified to setup the safe voltage levels during the changes
    in CPU clock speed.

(c) The CPU clock supply as been restructured as
    [ Output of APLL -> Opaque CPU clock provider -> CPU clock output ]
    And with the changes in (a) and (b) above, the cpufreq-cpu0 driver
    can now be used and can remove the use of Exynos specific
    cpufreq driver.

This patch series is tested on the following platforms.
  - Exynos4210 based Insignal Origen board.
  - Exynos4412 based Insignal Origen Quad board.
  - Exynos5250 based Samsung SMDK board.

This patch series is based on linux-next master branch.

Thomas Abraham (7):
  cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  clk: samsung: add infrastructure to register cpu clocks
  devicetree: bindings: add cpu clock configuration data binding for Exynos4/5
  ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table
  clk: exynos: use cpu-clock provider type to represent arm clock
  ARM: Exynos: switch to using generic cpufreq-cpu0 driver
  cpufreq: exynos: remove all exynos specific cpufreq driver support

 .../devicetree/bindings/clock/exynos4-clock.txt    |   30 ++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   22 ++
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 +
 arch/arm/boot/dts/exynos4210-origen.dts            |    6 +
 arch/arm/boot/dts/exynos4210-trats.dts             |    6 +
 arch/arm/boot/dts/exynos4210-universal_c210.dts    |    6 +
 arch/arm/boot/dts/exynos4210.dtsi                  |   35 ++
 arch/arm/boot/dts/exynos4212.dtsi                  |   17 +
 arch/arm/boot/dts/exynos4412-odroidx.dts           |    6 +
 arch/arm/boot/dts/exynos4412-origen.dts            |    6 +
 arch/arm/boot/dts/exynos4412-trats2.dts            |    6 +
 arch/arm/boot/dts/exynos4412.dtsi                  |   30 ++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   35 ++
 arch/arm/boot/dts/exynos5250-arndale.dts           |    6 +
 arch/arm/boot/dts/exynos5250-cros-common.dtsi      |    6 +
 arch/arm/boot/dts/exynos5250-smdk5250.dts          |    6 +
 arch/arm/boot/dts/exynos5250.dtsi                  |   43 +++-
 arch/arm/mach-exynos/common.c                      |    5 -
 arch/arm/mach-exynos/common.h                      |    1 -
 arch/arm/mach-exynos/mach-exynos4-dt.c             |    2 +-
 arch/arm/mach-exynos/mach-exynos5-dt.c             |    2 +-
 drivers/clk/samsung/Makefile                       |    2 +-
 drivers/clk/samsung/clk-cpu.c                      |  345 ++++++++++++++++++++
 drivers/clk/samsung/clk-exynos4.c                  |   11 +-
 drivers/clk/samsung/clk-exynos5250.c               |    8 +-
 drivers/clk/samsung/clk.h                          |    3 +
 drivers/cpufreq/Kconfig.arm                        |   36 --
 drivers/cpufreq/Makefile                           |    4 -
 drivers/cpufreq/cpufreq-cpu0.c                     |   37 ++-
 drivers/cpufreq/exynos-cpufreq.c                   |  292 -----------------
 drivers/cpufreq/exynos-cpufreq.h                   |   91 -----
 drivers/cpufreq/exynos4210-cpufreq.c               |  157 ---------
 drivers/cpufreq/exynos4x12-cpufreq.c               |  211 ------------
 drivers/cpufreq/exynos5250-cpufreq.c               |  183 -----------
 include/dt-bindings/clock/exynos5250.h             |    1 +
 35 files changed, 666 insertions(+), 998 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-cpu.c
 delete mode 100644 drivers/cpufreq/exynos-cpufreq.c
 delete mode 100644 drivers/cpufreq/exynos-cpufreq.h
 delete mode 100644 drivers/cpufreq/exynos4210-cpufreq.c
 delete mode 100644 drivers/cpufreq/exynos4x12-cpufreq.c
 delete mode 100644 drivers/cpufreq/exynos5250-cpufreq.c

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-20  8:09   ` Lukasz Majewski
                     ` (2 more replies)
  2014-01-18 12:10 ` [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks Thomas Abraham
                   ` (5 subsequent siblings)
  6 siblings, 3 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

On some platforms such as the Samsung Exynos, changing the frequency
of the CPU clock requires changing the frequency of the PLL that is
supplying the CPU clock. To change the frequency of the PLL, the CPU
clock is temporarily reparented to another parent clock.

The clock frequency of this temporary parent clock could be much higher
than the clock frequency of the PLL at the time of reparenting. Due
to the temporary increase in the CPU clock speed, the CPU (and any other
components in the CPU clock domain such as dividers, mux, etc.) have to
to be operated at a higher voltage level, called the safe voltage level.
This patch adds optional support to temporarily switch to a safe voltage
level during CPU frequency transitions.

Cc: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
 drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
index f055515..37453ab 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -19,6 +19,12 @@ Optional properties:
 - cooling-min-level:
 - cooling-max-level:
      Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
+- safe-opp: Certain platforms require that during a opp transition,
+  a system should not go below a particular opp level. For such systems,
+  this property specifies the minimum opp to be maintained during the
+  opp transitions. The safe-opp value is a tuple with first element
+  representing the safe frequency and the second element representing the
+  safe voltage.
 
 Examples:
 
@@ -36,6 +42,7 @@ cpus {
 			396000  950000
 			198000  850000
 		>;
+		safe-opp = <396000 950000>
 		clock-latency = <61036>; /* two CLK32 periods */
 		#cooling-cells = <2>;
 		cooling-min-level = <0>;
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 0c12ffc..075d3d1 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -27,6 +27,8 @@
 
 static unsigned int transition_latency;
 static unsigned int voltage_tolerance; /* in percentage */
+static unsigned long safe_frequency;
+static unsigned long safe_voltage;
 
 static struct device *cpu_dev;
 static struct clk *cpu_clk;
@@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
 		volt_old = regulator_get_voltage(cpu_reg);
 	}
 
-	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
+	pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
 		 old_freq / 1000, volt_old ? volt_old / 1000 : -1,
 		 new_freq / 1000, volt ? volt / 1000 : -1);
 
 	/* scaling up?  scale voltage before frequency */
-	if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
+	if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
+				new_freq >= safe_frequency) {
 		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
 		if (ret) {
 			pr_err("failed to scale voltage up: %d\n", ret);
 			return ret;
 		}
+	} else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
+		/*
+		 * the scaled up voltage level for the new_freq is lower
+		 * than the safe voltage level. so set safe_voltage
+		 * as the intermediate voltage level and revert it
+		 * back after the frequency has been changed.
+		 */
+		ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
+		if (ret) {
+			pr_err("failed to set safe voltage: %d\n", ret);
+			return ret;
+		}
 	}
 
 	ret = clk_set_rate(cpu_clk, freq_exact);
@@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
 	}
 
 	/* scaling down?  scale voltage after frequency */
-	if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
+	if (!IS_ERR(cpu_reg) &&
+			(new_freq < old_freq || new_freq < safe_frequency)) {
 		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
 		if (ret) {
 			pr_err("failed to scale voltage down: %d\n", ret);
@@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
 
 static int cpu0_cpufreq_probe(struct platform_device *pdev)
 {
+	const struct property *prop;
+	struct dev_pm_opp *opp;
 	struct device_node *np;
 	int ret;
 
@@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 		goto out_put_node;
 	}
 
+	prop = of_find_property(np, "safe-opp", NULL);
+	if (prop) {
+		if (prop->value && (prop->length / sizeof(u32)) == 2) {
+			const __be32 *val;
+			val = prop->value;
+			safe_frequency = be32_to_cpup(val++);
+			safe_voltage = be32_to_cpup(val);
+		} else {
+			pr_err("invalid safe-opp level specified\n");
+		}
+	}
+
 	of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
 
 	if (of_property_read_u32(np, "clock-latency", &transition_latency))
 		transition_latency = CPUFREQ_ETERNAL;
 
 	if (!IS_ERR(cpu_reg)) {
-		struct dev_pm_opp *opp;
 		unsigned long min_uV, max_uV;
 		int i;
 
-- 
1.6.6.rc2

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

* [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
  2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-20  8:24   ` Lukasz Majewski
  2014-01-18 12:10 ` [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5 Thomas Abraham
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

The CPU clock provider supplies the clock to the CPU clock domain. The
composition and organization of the CPU clock provider could vary among
Exynos SoCs. A CPU clock provider can be composed of clock mux, dividers
and gates. This patch defines a new clock type for CPU clock provider and
adds infrastructure to register the CPU clock providers for Samsung
platforms.

In addition to this, the arm cpu clock provider for Exynos4210 and
compatible SoCs is instantiated using the new cpu clock type. The clock
frequency table and the clock configuration data for this clock is
obtained from device tree. This implementation is reusable for Exynos4x12
and Exynos5250 SoCs as well.

Cc: Tomasz Figa <t.figa@samsung.com>
Cc: Lukasz Majewski <l.majewski@majess.pl>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 drivers/clk/samsung/Makefile  |    2 +-
 drivers/clk/samsung/clk-cpu.c |  345 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h     |    3 +
 3 files changed, 349 insertions(+), 1 deletions(-)
 create mode 100644 drivers/clk/samsung/clk-cpu.c

diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 8eb4799..e2b453f 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -2,7 +2,7 @@
 # Samsung Clock specific Makefile
 #
 
-obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o
+obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o clk-cpu.o
 obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
 obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o
 obj-$(CONFIG_SOC_EXYNOS5420)	+= clk-exynos5420.o
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
new file mode 100644
index 0000000..92fba45
--- /dev/null
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * 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 contains the utility functions to register the cpu clocks
+ * for samsung platforms.
+*/
+
+#include <linux/errno.h>
+#include "clk.h"
+
+#define SRC_CPU			0x0
+#define STAT_CPU		0x200
+#define DIV_CPU0		0x300
+#define DIV_CPU1		0x304
+#define DIV_STAT_CPU0		0x400
+#define DIV_STAT_CPU1		0x404
+
+/**
+ * struct samsung_cpuclk_freq_table: table of frequency supported by
+ * a cpu clock and associated data if any.
+ * @freq: points to a table of supported frequencies (in KHz)
+ * @freq_count: number of entries in the frequency table
+ * @data: cpu clock specific data, if any
+ *
+ * This structure holds the frequency options supported by the cpu clock in
+ * which this structure is contained. The data pointer is an optional data
+ * that can provide any additional configuration options for the supported
+ * frequencies. This structure is intended to be reusable for all cpu clocks
+ * in Samsung SoC based platforms
+ */
+struct samsung_cpuclk_freq_table {
+	const unsigned long	*freq;       /* in KHz */
+	unsigned long		freq_count;
+	const void		*data;
+};
+
+/**
+ * struct exynos4210_freq_data: format of auxillary data associated with
+ * each frequency supported by the cpu clock for exynos4210.
+ * @parent_freq: The frequency of the parent clock required to generate the
+ * supported cpu clock speed.
+ * @div0: value to be programmed in the div_cpu0 register.
+ * @div1: value to be programmed in the div_cpu1 register.
+ *
+ * This structure holds the auxillary configuration data for each supported
+ * cpu clock frequency on Exynos4210 and compatible SoCs.
+ */
+struct exynos4210_freq_data {
+	unsigned long	parent_freq;
+	unsigned int	div0;
+	unsigned int	div1;
+};
+
+/**
+ * struct samsung_cpuclk: information about clock supplied to a CPU core.
+ * @hw: handle between ccf and cpu clock.
+ * @ctrl_base: base address of the clock controller.
+ * @offset: offset from the ctrl_base address where the cpu clock div/mux
+ *          registers can be accessed.
+ * @parent: clock handle representing the clock output of the parent clock.
+ * @freq_table: the frequency table supported by this cpu clock.
+ */
+struct samsung_cpuclk {
+	struct clk_hw		hw;
+	void __iomem		*ctrl_base;
+	unsigned long		offset;
+	struct clk		*parent;
+	const struct samsung_cpuclk_freq_table *freq_table;
+};
+
+#define to_samsung_cpuclk(hw)	container_of(hw, struct samsung_cpuclk, hw)
+
+/**
+ * struct samsung_cpuclk_match_data: soc specific data for cpu clocks.
+ * @parser: pointer to a function that can parse SoC specific cpu clock
+ *	frequency and associated configuration data.
+ * @offset: optional offset from base of clock controller register base,
+ *	to be used when accessing clock controller registers related to the
+ * cpu clock.
+ * @offset: offset from the ctrl_base address where the cpu clock div/mux
+ *	registers can be accessed.
+ */
+struct samsung_cpuclk_match_data {
+	int (*parser)(struct device_node *,
+			struct samsung_cpuclk_freq_table **);
+	unsigned int offset;
+};
+
+/* This is a helper function to perform clock rounding for cpu clocks. */
+static long samsung_cpuclk_round_rate(struct clk_hw *hw,
+			unsigned long drate, unsigned long *prate)
+{
+	struct samsung_cpuclk *cpuclk = to_samsung_cpuclk(hw);
+	const struct samsung_cpuclk_freq_table *freq_tbl;
+	int i;
+
+	freq_tbl = cpuclk->freq_table;
+	drate /= 1000;
+
+	for (i = 0; i < freq_tbl->freq_count; i++) {
+		if (drate >= freq_tbl->freq[i])
+			return freq_tbl->freq[i] * 1000;
+	}
+	return freq_tbl->freq[i - 1] * 1000;
+}
+
+#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
+#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf) + 1)
+
+/*
+ * CPU clock speed for Exynos4210 and compatible SoCs is
+ * parent clock speed / core1_ratio / core2_ratio
+ */
+static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
+	void __iomem *base = armclk->ctrl_base + armclk->offset;
+
+	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
+				EXYNOS4210_ARM_DIV2(base);
+}
+
+/* set rate callback for cpuclk type on Exynos4210 and similar SoCs */
+static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long prate)
+{
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
+	const struct samsung_cpuclk_freq_table *freq_tbl;
+	const struct exynos4210_freq_data *freq_data;
+	unsigned long mux_reg, idx;
+	void __iomem *base;
+
+	if (drate == prate)
+		return 0;
+
+	freq_tbl = armclk->freq_table;
+	freq_data = freq_tbl->data;
+	base = armclk->ctrl_base + armclk->offset;
+
+	for (idx = 0; idx < freq_tbl->freq_count; idx++, freq_data++)
+		if ((freq_tbl->freq[idx] * 1000) == drate)
+			break;
+
+	if (drate < prate) {
+		mux_reg = readl(base + SRC_CPU);
+		writel(mux_reg | (1 << 16), base + SRC_CPU);
+		while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
+			;
+
+		clk_set_rate(armclk->parent, drate);
+	}
+
+	writel(freq_data->div0, base + DIV_CPU0);
+	while (readl(base + DIV_STAT_CPU0) != 0)
+		;
+	writel(freq_data->div1, base + DIV_CPU1);
+	while (readl(base + DIV_STAT_CPU1) != 0)
+		;
+
+	if (drate > prate) {
+		mux_reg = readl(base + SRC_CPU);
+		writel(mux_reg | (1 << 16), base + SRC_CPU);
+		while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
+			;
+
+		clk_set_rate(armclk->parent, freq_data->parent_freq * 1000);
+	}
+
+	mux_reg = readl(base + SRC_CPU);
+	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
+	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
+			;
+	return 0;
+}
+
+/* clock ops for armclk on Exynos4210 and compatible platforms. */
+static const struct clk_ops exynos4210_armclk_clk_ops = {
+	.recalc_rate = exynos4210_armclk_recalc_rate,
+	.round_rate = samsung_cpuclk_round_rate,
+	.set_rate = exynos4210_armclk_set_rate,
+};
+
+/* helper function to register a cpu clock */
+static void __init samsung_cpuclk_register(unsigned int lookup_id,
+		const char *name, const char *parent, const struct clk_ops *ops,
+		const struct samsung_cpuclk_freq_table *freq_tbl,
+		void __iomem *reg_base,
+		const struct samsung_cpuclk_match_data *data)
+{
+	struct samsung_cpuclk *cpuclk;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
+	if (!cpuclk) {
+		pr_err("%s: could not allocate memory for cpuclk %s\n",
+					__func__, name);
+		return;
+	}
+
+	init.name = name;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &parent;
+	init.num_parents = 1;
+	init.ops = ops;
+
+	cpuclk->hw.init = &init;
+	cpuclk->ctrl_base = reg_base;
+	cpuclk->offset = data->offset;
+	cpuclk->freq_table = freq_tbl;
+	cpuclk->parent = __clk_lookup(parent);
+
+	clk = clk_register(NULL, &cpuclk->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
+		kfree(cpuclk);
+		return;
+	}
+	samsung_clk_add_lookup(clk, lookup_id);
+}
+
+#define EXYNOS4210_DIV_CPU01(d0, d1, d2, d3, d4, d5, d6, d7)		\
+		((d0 << 28) | (d1 << 24) | (d2 << 20) |	(d3 << 16) |	\
+		 (d4 << 12) | (d5 << 8) | (d6 << 4) | (d7 << 0))
+#define EXYNOS4210_DIV_CPU11(d0, d1, d2)				\
+		((d0 << 8) | (d1 << 4) | (d2 << 0))
+#define EXYNOS4210_CFG_LEN 13
+
+/*
+ * parse cpu clock frequency table and auxillary configuration data from dt
+ * for exynos4210 and compatible SoC's.
+ */
+static int exynos4210_armclk_cfg_parser(struct device_node *np,
+		struct samsung_cpuclk_freq_table **tbl)
+{
+	struct samsung_cpuclk_freq_table *freq_tbl;
+	struct exynos4210_freq_data *fdata, *t_fdata;
+	unsigned long *freqs, cfg[EXYNOS4210_CFG_LEN];
+	const struct property *prop;
+	unsigned int tbl_sz, i, j;
+	const __be32 *val;
+	int ret;
+
+	prop = of_find_property(np, "arm-frequency-table", NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -EINVAL;
+	if ((prop->length / sizeof(u32)) % EXYNOS4210_CFG_LEN)
+		return -EINVAL;
+	tbl_sz = (prop->length / sizeof(u32)) / EXYNOS4210_CFG_LEN;
+
+	freq_tbl = kzalloc(sizeof(*freq_tbl), GFP_KERNEL);
+	if (!freq_tbl)
+		return -ENOMEM;
+
+	freqs = kzalloc(sizeof(u32) * tbl_sz, GFP_KERNEL);
+	if (!freqs) {
+		ret = -ENOMEM;
+		goto free_freq_tbl;
+	}
+
+	fdata = kzalloc(sizeof(*fdata) * tbl_sz, GFP_KERNEL);
+	if (!fdata) {
+		ret = -ENOMEM;
+		goto free_freqs;
+	}
+	t_fdata = fdata;
+
+	val = prop->value;
+	for (i = 0; i < tbl_sz; i++, fdata++) {
+		for (j = 0; j < EXYNOS4210_CFG_LEN; j++)
+			cfg[j] = be32_to_cpup(val++);
+		freqs[i] = cfg[0];
+		fdata->parent_freq = cfg[1];
+		fdata->div0 = EXYNOS4210_DIV_CPU01(cfg[9], cfg[8], cfg[7],
+				cfg[6], cfg[5], cfg[4], cfg[3], cfg[2]);
+		fdata->div1 = EXYNOS4210_DIV_CPU11(cfg[12], cfg[11], cfg[10]);
+	}
+
+	freq_tbl->freq = freqs;
+	freq_tbl->freq_count = tbl_sz;
+	freq_tbl->data = t_fdata;
+	*tbl = freq_tbl;
+	return 0;
+
+free_freqs:
+	kfree(freqs);
+free_freq_tbl:
+	kfree(freq_tbl);
+	return ret;
+}
+
+static struct samsung_cpuclk_match_data exynos4210_cpuclk_match_data = {
+	.parser = exynos4210_armclk_cfg_parser,
+	.offset = 0x14200,
+};
+
+static struct samsung_cpuclk_match_data exynos5250_cpuclk_match_data = {
+	.parser = exynos4210_armclk_cfg_parser,
+	.offset = 0x200,
+};
+
+static const struct of_device_id samsung_clock_ids[] = {
+	{ .compatible = "samsung,exynos4210-clock",
+			.data = &exynos4210_cpuclk_match_data, },
+	{ .compatible = "samsung,exynos4412-clock",
+			.data = &exynos4210_cpuclk_match_data, },
+	{ .compatible = "samsung,exynos5250-clock",
+			.data = &exynos5250_cpuclk_match_data, },
+};
+
+int __init samsung_register_arm_clock(struct device_node *np,
+		unsigned int lookup_id,	const char *parent, void __iomem *base)
+{
+	const struct of_device_id *match;
+	struct samsung_cpuclk_freq_table *freq_table;
+	const struct samsung_cpuclk_match_data *data;
+	int ret;
+
+	match = of_match_node(samsung_clock_ids, np);
+	if (!match) {
+		pr_err("%s: could not determine soc type\n", __func__);
+		return -EINVAL;
+	}
+
+	data = match->data;
+	ret = data->parser(np, &freq_table);
+	if (ret) {
+		pr_err("%s: error %d in parsing arm clock freq table",
+						__func__, ret);
+		return -EINVAL;
+	}
+
+	samsung_cpuclk_register(lookup_id, "armclk", parent,
+		&exynos4210_armclk_clk_ops, freq_table, base, data);
+
+	return 0;
+}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 31b4174..a759330 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -340,4 +340,7 @@ extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
 
 extern unsigned long _get_rate(const char *clk_name);
 
+extern int __init samsung_register_arm_clock(struct device_node *np,
+		unsigned int lookup_id, const char *parent, void __iomem *base);
+
 #endif /* __SAMSUNG_CLK_H */
-- 
1.6.6.rc2

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

* [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
  2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
  2014-01-18 12:10 ` [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-18 15:22   ` Rob Herring
  2014-01-18 12:10 ` [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table Thomas Abraham
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

The clk ops of the new Samsung cpu clock provider type requires configuration
data that will be programmed in the multiple clock blocks encapsulated within
the cpu clock provider type. This configuration data is held in the clock
controller node. Update clock binding documentation about this configuration
data format for Samsung Exynos4 and Exynos5 platforms.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Tomasz Figa <t.figa@samsung.com>
Cc: <devicetree@vger.kernel.org>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/clock/exynos4-clock.txt    |   30 ++++++++++++++++++++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   21 ++++++++++++++
 2 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
index a2ac2d9..c28aabd 100644
--- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
@@ -15,6 +15,29 @@ Required Properties:
 
 - #clock-cells: should be 1.
 
+- arm-frequency-table: defines the list of arm clock speeds supported and
+  the associated configuration values required to setup the clock controller
+  for generating those speeds. The format of each entry included in the
+  arm-frequency-table should be as defined below (#cells per entry = 13)
+
+  - for Exynos4210 and Exynos4212 based platforms:
+      cell #1: arm clock frequency
+      cell #2: expected arm clock parent frequency
+      cell #3 ~ cell 12#: value of clock divider in the following order
+	       core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
+	       atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
+	       copy_ratio, hpm_ratio.
+      cell #13: reserved (should be zero).
+
+  - for Exynos4412 based platforms:
+      cell #1: arm clock frequency
+      cell #2: expected arm clock parent frequency
+      cell #3 ~ cell #13: value of clock divider in the following order
+	       core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
+	       atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
+	       copy_ratio, hpm_ratio, cores_ratio
+
+
 The following is the list of clocks generated by the controller. Each clock is
 assigned an identifier and client nodes use this identifier to specify the
 clock which they consume. Some of the clocks are available only on a particular
@@ -275,6 +298,13 @@ Example 1: An example of a clock controller node is listed below.
 		compatible = "samsung,exynos4210-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7 0 5 0>,
+				      <1000000 1000000 0 3 7 3 4 1 7 0 4 0>,
+				      < 800000  800000 0 3 7 3 3 1 7 0 3 0>,
+				      < 500000  500000 0 3 7 3 3 1 7 0 3 0>,
+				      < 400000  400000 0 3 7 3 3 1 7 0 3 0>,
+				      < 200000  200000 0 1 3 1 1 1 0 0 3 0>;
 	};
 
 Example 2: UART controller node that consumes the clock generated by the clock
diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 72ce617..99eae9c 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -13,6 +13,20 @@ Required Properties:
 
 - #clock-cells: should be 1.
 
+- arm-frequency-table: defines the list of arm clock speeds supported and
+  the associated configuration values required to setup the clock controller
+  for generating those speeds. The format of each entry included in the
+  arm-frequency-table should be as defined below (#cells per entry = 13)
+
+      cell #1: arm clock frequency
+      cell #2: expected arm clock parent frequency
+      cell #3 ~ cell #12: value of clock divider in the following order
+	       arm_ratio, cpud_ratio, acp_ratio, periph_ratio,
+	       atb_ratio, pclk_dbg_ratio, apll_ratio, arm2_ratio,
+	       copy_ratio, hpm_ratio
+      cell #13: reserved (should be zero)
+
+
 The following is the list of clocks generated by the controller. Each clock is
 assigned an identifier and client nodes use this identifier to specify the
 clock which they consume.
@@ -177,6 +191,13 @@ Example 1: An example of a clock controller node is listed below.
 		compatible = "samsung,exynos5250-clock";
 		reg = <0x10010000 0x30000>;
 		#clock-cells = <1>;
+
+		arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5 0 0 2>,
+				      <1600000 1600000 0 3 7 7 7 1 4 0 0 2>,
+				      <1500000 1500000 0 2 7 7 7 1 4 0 0 2>,
+				      <1400000 1400000 0 2 7 7 6 1 4 0 0 2>,
+				      <1300000 1300000 0 2 7 7 6 1 3 0 0 2>,
+				      <1200000 1200000 0 2 7 7 5 1 3 0 0 2>;
 	};
 
 Example 2: UART controller node that consumes the clock generated by the clock
-- 
1.6.6.rc2

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

* [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
                   ` (2 preceding siblings ...)
  2014-01-18 12:10 ` [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5 Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-20  7:32   ` Lukasz Majewski
  2014-01-18 12:10 ` [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock Thomas Abraham
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

For all Exynos based platforms, add CPU nodes, operating points and cpu
clock frequency table for migrating from Exynos specific cpufreq driver
to using generic cpufreq-cpu0 driver.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 arch/arm/boot/dts/exynos4210-origen.dts         |    6 +++
 arch/arm/boot/dts/exynos4210-trats.dts          |    6 +++
 arch/arm/boot/dts/exynos4210-universal_c210.dts |    6 +++
 arch/arm/boot/dts/exynos4210.dtsi               |   35 ++++++++++++++++++
 arch/arm/boot/dts/exynos4212.dtsi               |   17 +++++++++
 arch/arm/boot/dts/exynos4412-odroidx.dts        |    6 +++
 arch/arm/boot/dts/exynos4412-origen.dts         |    6 +++
 arch/arm/boot/dts/exynos4412-trats2.dts         |    6 +++
 arch/arm/boot/dts/exynos4412.dtsi               |   30 ++++++++++++++++
 arch/arm/boot/dts/exynos4x12.dtsi               |   35 ++++++++++++++++++
 arch/arm/boot/dts/exynos5250-arndale.dts        |    6 +++
 arch/arm/boot/dts/exynos5250-cros-common.dtsi   |    6 +++
 arch/arm/boot/dts/exynos5250-smdk5250.dts       |    6 +++
 arch/arm/boot/dts/exynos5250.dtsi               |   43 ++++++++++++++++++++++-
 14 files changed, 213 insertions(+), 1 deletions(-)

diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
index 2aa13cb..dd17e93 100644
--- a/arch/arm/boot/dts/exynos4210-origen.dts
+++ b/arch/arm/boot/dts/exynos4210-origen.dts
@@ -32,6 +32,12 @@
 		bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck1_reg>;
+		};
+	};
+
 	regulators {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 63cc571..25487d7 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -30,6 +30,12 @@
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
 	};
 
+	cpus {
+		cpu: cpu at 0 {
+			cpu0-supply = <&varm_breg>;
+		};
+	};
+
 	regulators {
 		compatible = "simple-bus";
 
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index d2e3f5f..74d5a70 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -28,6 +28,12 @@
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1";
 	};
 
+	cpus {
+		cpu: cpu at 0 {
+			cpu0-supply = <&vdd_arm_reg>;
+		};
+	};
+
 	mct at 10050000 {
 		compatible = "none";
 	};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 48ecd7a..40cd663 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -36,6 +36,34 @@
 		reg = <0x10023CA0 0x20>;
 	};
 
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			clocks = <&clock 12>;
+			clock-names = "cpu";
+
+			operating-points = <
+				200000	950000
+				400000	975000
+				500000	975000
+				800000	1075000
+				1000000	1150000
+				1200000	1250000
+			>;
+			safe-opp = <800000 1075000>;
+		};
+
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+		};
+	};
+
 	gic: interrupt-controller at 10490000 {
 		cpu-offset = <0x8000>;
 	};
@@ -73,6 +101,13 @@
 		compatible = "samsung,exynos4210-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7 0 5 0 0>,
+				      <1000000 1000000 0 3 7 3 4 1 7 0 4 0 0>,
+				      < 800000  800000 0 3 7 3 3 1 7 0 3 0 0>,
+				      < 500000  500000 0 3 7 3 3 1 7 0 3 0 0>,
+				      < 400000  400000 0 3 7 3 3 1 7 0 3 0 0>,
+				      < 200000  200000 0 1 3 1 1 1 0 0 3 0 0>;
 	};
 
 	pmu {
diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
index 94a43f9..2ea0f83 100644
--- a/arch/arm/boot/dts/exynos4212.dtsi
+++ b/arch/arm/boot/dts/exynos4212.dtsi
@@ -22,6 +22,23 @@
 / {
 	compatible = "samsung,exynos4212";
 
+	clock: clock-controller at 10030000 {
+		arm-frequency-table = <1500000 1500000 0 3 7 0 6 1 2 0 6 2 0>,
+				      <1400000 1400000 0 3 7 0 6 1 2 0 6 2 0>,
+				      <1300000 1300000 0 3 7 0 5 1 2 0 5 2 0>,
+				      <1200000 1200000 0 3 7 0 5 1 2 0 5 2 0>,
+				      <1100000 1100000 0 3 6 0 4 1 2 0 4 2 0>,
+				      <1000000 1000000 0 2 5 0 4 1 1 0 4 2 0>,
+				      < 900000  900000 0 2 5 0 3 1 1 0 3 2 0>,
+				      < 800000  800000 0 2 5 0 3 1 1 0 3 2 0>,
+				      < 700000  700000 0 2 4 0 3 1 1 0 3 2 0>,
+				      < 600000  600000 0 2 4 0 3 1 1 0 3 2 0>,
+				      < 500000  500000 0 2 4 0 3 1 1 0 3 2 0>,
+				      < 400000  400000 0 2 4 0 3 1 1 0 3 2 0>,
+				      < 300000  300000 0 2 4 0 2 1 1 0 3 2 0>,
+				      < 200000  200000 0 1 3 0 1 1 1 0 3 2 0>;
+	};
+
 	gic: interrupt-controller at 10490000 {
 		cpu-offset = <0x8000>;
 	};
diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts
index 12459b0..1c751f9 100644
--- a/arch/arm/boot/dts/exynos4412-odroidx.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidx.dts
@@ -22,6 +22,12 @@
 		reg = <0x40000000 0x40000000>;
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		led1 {
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index 388f035..36080e5 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -27,6 +27,12 @@
 		bootargs ="console=ttySAC2,115200";
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	firmware at 0203F000 {
 		compatible = "samsung,secure-firmware";
 		reg = <0x0203F000 0x1000>;
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 4f851cc..4a4d446 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -31,6 +31,12 @@
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	firmware at 0204F000 {
 		compatible = "samsung,secure-firmware";
 		reg = <0x0204F000 0x1000>;
diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
index 87b339c..7e9eca7 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -22,6 +22,36 @@
 / {
 	compatible = "samsung,exynos4412";
 
+	cpus {
+		cpu at 2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <2>;
+		};
+		cpu at 3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <3>;
+		};
+	};
+
+	clock: clock-controller at 10030000 {
+		arm-frequency-table = <1500000 1500000 0 3 7 0 6 1 2 0 6 0 7>,
+				      <1400000 1400000 0 3 7 0 6 1 2 0 6 0 6>,
+				      <1300000 1300000 0 3 7 0 5 1 2 0 5 0 6>,
+				      <1200000 1200000 0 3 7 0 5 1 2 0 5 0 5>,
+				      <1100000 1100000 0 3 6 0 4 1 2 0 4 0 5>,
+				      <1000000 1000000 0 2 5 0 4 1 1 0 4 0 4>,
+				      < 900000  900000 0 2 5 0 3 1 1 0 3 0 4>,
+				      < 800000  800000 0 2 5 0 3 1 1 0 3 0 3>,
+				      < 700000  700000 0 2 4 0 3 1 1 0 3 0 3>,
+				      < 600000  600000 0 2 4 0 3 1 1 0 3 0 2>,
+				      < 500000  500000 0 2 4 0 3 1 1 0 3 0 2>,
+				      < 400000  400000 0 2 4 0 3 1 1 0 3 0 1>,
+				      < 300000  300000 0 2 4 0 2 1 1 0 3 0 1>,
+				      < 200000  200000 0 1 3 0 1 1 1 0 3 0 0>;
+	};
+
 	gic: interrupt-controller at 10490000 {
 		cpu-offset = <0x4000>;
 	};
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 5c412aa..47e2195 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -31,6 +31,41 @@
 		mshc0 = &mshc_0;
 	};
 
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			clocks = <&clock 12>;
+			clock-names = "cpu";
+
+			operating-points = <
+				1400000 1350000
+				1300000 1287500
+				1200000 1250000
+				1100000 1187500
+				1000000 1137500
+				 900000 1087500
+				 800000 1037500
+				 700000 1000000
+				 600000  987500
+				 500000  950000
+				 400000  925000
+				 300000  900000
+				 200000  900000
+			>;
+			clock-latency = <200000>;
+			safe-opp = <800000 1037500>;
+		};
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+		};
+	};
+
 	pd_isp: isp-power-domain at 10023CA0 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023CA0 0x20>;
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index b42e658..4716eef 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -25,6 +25,12 @@
 		bootargs = "console=ttySAC2,115200";
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	codec at 11000000 {
 		samsung,mfc-r = <0x43000000 0x800000>;
 		samsung,mfc-l = <0x51000000 0x800000>;
diff --git a/arch/arm/boot/dts/exynos5250-cros-common.dtsi b/arch/arm/boot/dts/exynos5250-cros-common.dtsi
index 2c1560d..4bde756 100644
--- a/arch/arm/boot/dts/exynos5250-cros-common.dtsi
+++ b/arch/arm/boot/dts/exynos5250-cros-common.dtsi
@@ -19,6 +19,12 @@
 	chosen {
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	pinctrl at 11400000 {
 		/*
 		 * Disabled pullups since external part has its own pullups and
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 5c1b7d9..7c228e2 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -27,6 +27,12 @@
 		bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
 	};
 
+	cpus {
+		cpu at 0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	i2c at 12C60000 {
 		samsung,i2c-sda-delay = <100>;
 		samsung,i2c-max-bus-freq = <20000>;
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index b7dec41..d2f98dc 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -61,6 +61,30 @@
 			compatible = "arm,cortex-a15";
 			reg = <0>;
 			clock-frequency = <1700000000>;
+
+			clocks = <&clock 12>;
+			clock-names = "cpu";
+
+			operating-points = <
+				1700000 1300000
+				1600000 1250000
+				1500000 1225000
+				1400000 1200000
+				1300000 1150000
+				1200000 1125000
+				1100000 1100000
+				1000000 1075000
+				 900000 1050000
+				 800000 1025000
+				 700000 1012500
+				 600000 1000000
+				 500000  975000
+				 400000  950000
+				 300000  937500
+				 200000  925000
+			>;
+			clock-latency = <200000>;
+			safe-opp = <800000 1025000>;
 		};
 		cpu at 1 {
 			device_type = "cpu";
@@ -84,7 +108,24 @@
 		compatible = "samsung,exynos5250-clock";
 		reg = <0x10010000 0x30000>;
 		#clock-cells = <1>;
-	};
+
+		arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5 0 0 2 0>,
+				      <1600000 1600000 0 3 7 7 7 1 4 0 0 2 0>,
+				      <1500000 1500000 0 2 7 7 7 1 4 0 0 2 0>,
+				      <1400000 1400000 0 2 7 7 6 1 4 0 0 2 0>,
+				      <1300000 1300000 0 2 7 7 6 1 3 0 0 2 0>,
+				      <1200000 1200000 0 2 7 7 5 1 3 0 0 2 0>,
+				      <1100000 1100000 0 3 7 7 5 1 3 0 0 2 0>,
+				      <1000000 1000000 0 1 7 7 4 1 2 0 0 2 0>,
+				      < 900000  900000 0 1 7 7 4 1 2 0 0 2 0>,
+				      < 800000  800000 0 1 7 7 4 1 2 0 0 2 0>,
+				      < 700000  700000 0 1 7 7 3 1 1 0 0 2 0>,
+				      < 600000  600000 0 1 7 7 3 1 1 0 0 2 0>,
+				      < 500000  500000 0 1 7 7 2 1 1 0 0 2 0>,
+				      < 400000  400000 0 1 7 7 2 1 1 0 0 2 0>,
+				      < 300000  300000 0 1 7 7 1 1 1 0 0 2 0>,
+				      < 200000  200000 0 1 7 7 1 1 1 0 0 2 0>;
+	};
 
 	clock_audss: audss-clock-controller at 3810000 {
 		compatible = "samsung,exynos5250-audss-clock";
-- 
1.6.6.rc2

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

* [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
                   ` (3 preceding siblings ...)
  2014-01-18 12:10 ` [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-20  7:47   ` Lukasz Majewski
  2014-01-18 12:10 ` [PATCH v2 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver Thomas Abraham
  2014-01-18 12:10 ` [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support Thomas Abraham
  6 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

With the addition of the new Samsung specific cpu-clock type, the
arm clock can be represented as a cpu-clock type and the independent
clock blocks that made up the arm clock can be removed.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
 drivers/clk/samsung/clk-exynos4.c                  |   11 +++++------
 drivers/clk/samsung/clk-exynos5250.c               |    8 ++++----
 include/dt-bindings/clock/exynos5250.h             |    1 +
 4 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 99eae9c..acf867a 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -38,6 +38,7 @@ clock which they consume.
   ----------------------------
 
   fin_pll		1
+  armclk		12
 
   [Clock Gate for Special Clocks]
 
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 010f071..efcf4a3 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -437,8 +437,6 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
 
 /* list of divider clocks supported in all exynos4 soc's */
 static struct samsung_div_clock exynos4_div_clks[] __initdata = {
-	DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3),
-	DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3),
 	DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
 	DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
 	DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
@@ -484,8 +482,8 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = {
 	DIV(0, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),
 	DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
 	DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
-	DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
-	DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3),
+	DIV_F(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3,
+			CLK_GET_RATE_NOCACHE, 0),
 	DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
 			CLK_SET_RATE_PARENT, 0),
 	DIV_F(0, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
@@ -870,7 +868,6 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
 
 static struct samsung_clock_alias exynos4_aliases[] __initdata = {
 	ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
-	ALIAS(CLK_ARM_CLK, NULL, "armclk"),
 	ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"),
 };
 
@@ -1125,12 +1122,14 @@ static void __init exynos4_clk_init(struct device_node *np,
 	samsung_clk_register_alias(exynos4_aliases,
 			ARRAY_SIZE(exynos4_aliases));
 
+	samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll", reg_base);
+
 	pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
 		"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
 		exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
 		_get_rate("sclk_apll"),	_get_rate("sclk_mpll"),
 		_get_rate("sclk_epll"), _get_rate("sclk_vpll"),
-		_get_rate("arm_clk"));
+		_get_rate("armclk"));
 }
 
 
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index ff4beeb..487be36 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -298,9 +298,8 @@ static struct samsung_div_clock exynos5250_div_clks[] __initdata = {
 	/*
 	 * CMU_CPU
 	 */
-	DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
-	DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
-	DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3, "armclk"),
+	DIV_F(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
+			CLK_GET_RATE_NOCACHE, 0),
 
 	/*
 	 * CMU_TOP
@@ -684,8 +683,9 @@ static void __init exynos5250_clk_init(struct device_node *np)
 			ARRAY_SIZE(exynos5250_div_clks));
 	samsung_clk_register_gate(exynos5250_gate_clks,
 			ARRAY_SIZE(exynos5250_gate_clks));
+	samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll", reg_base);
 
 	pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
-			_get_rate("div_arm2"));
+			_get_rate("armclk"));
 }
 CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init);
diff --git a/include/dt-bindings/clock/exynos5250.h b/include/dt-bindings/clock/exynos5250.h
index 922f2dc..59a10fb 100644
--- a/include/dt-bindings/clock/exynos5250.h
+++ b/include/dt-bindings/clock/exynos5250.h
@@ -21,6 +21,7 @@
 #define CLK_FOUT_CPLL		6
 #define CLK_FOUT_EPLL		7
 #define CLK_FOUT_VPLL		8
+#define CLK_ARM_CLK		12
 
 /* gate for special clocks (sclk) */
 #define CLK_SCLK_CAM_BAYER	128
-- 
1.6.6.rc2

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

* [PATCH v2 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
                   ` (4 preceding siblings ...)
  2014-01-18 12:10 ` [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-20  7:48   ` Lukasz Majewski
  2014-01-18 12:10 ` [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support Thomas Abraham
  6 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

Remove the platform device instantiation for Exynos specific cpufreq
driver and add the platform device for cpufreq-cpu0 driver.

Cc: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 arch/arm/mach-exynos/common.c          |    5 -----
 arch/arm/mach-exynos/common.h          |    1 -
 arch/arm/mach-exynos/mach-exynos4-dt.c |    2 +-
 arch/arm/mach-exynos/mach-exynos5-dt.c |    2 +-
 4 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index f18be40..72ae5d3 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -303,11 +303,6 @@ void __init exynos_cpuidle_init(void)
 	platform_device_register(&exynos_cpuidle);
 }
 
-void __init exynos_cpufreq_init(void)
-{
-	platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
-}
-
 void __init exynos_init_late(void)
 {
 	if (of_machine_is_compatible("samsung,exynos5440"))
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index f76967b..0c31b34 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -22,7 +22,6 @@ void exynos_init_io(void);
 void exynos4_restart(enum reboot_mode mode, const char *cmd);
 void exynos5_restart(enum reboot_mode mode, const char *cmd);
 void exynos_cpuidle_init(void);
-void exynos_cpufreq_init(void);
 void exynos_init_late(void);
 
 void exynos_firmware_init(void);
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c
index d3e54b7..9a25320 100644
--- a/arch/arm/mach-exynos/mach-exynos4-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos4-dt.c
@@ -22,8 +22,8 @@
 static void __init exynos4_dt_machine_init(void)
 {
 	exynos_cpuidle_init();
-	exynos_cpufreq_init();
 
+	platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0);
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c
index 37ea261..9dc3710 100644
--- a/arch/arm/mach-exynos/mach-exynos5-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos5-dt.c
@@ -44,8 +44,8 @@ static void __init exynos5_dt_machine_init(void)
 	}
 
 	exynos_cpuidle_init();
-	exynos_cpufreq_init();
 
+	platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0);
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
-- 
1.6.6.rc2

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
                   ` (5 preceding siblings ...)
  2014-01-18 12:10 ` [PATCH v2 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver Thomas Abraham
@ 2014-01-18 12:10 ` Thomas Abraham
  2014-01-20  8:08   ` Lukasz Majewski
  6 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-18 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

From: Thomas Abraham <thomas.ab@samsung.com>

Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched over
to use cpufreq-cpu0 driver for cpufreq functionality. So the Exynos
specific cpufreq drivers for these platforms can be removed.

Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Jaecheol Lee <jc.lee@samsung.com>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 drivers/cpufreq/Kconfig.arm          |   36 ----
 drivers/cpufreq/Makefile             |    4 -
 drivers/cpufreq/exynos-cpufreq.c     |  292 ----------------------------------
 drivers/cpufreq/exynos-cpufreq.h     |   91 -----------
 drivers/cpufreq/exynos4210-cpufreq.c |  157 ------------------
 drivers/cpufreq/exynos4x12-cpufreq.c |  211 ------------------------
 drivers/cpufreq/exynos5250-cpufreq.c |  183 ---------------------
 7 files changed, 0 insertions(+), 974 deletions(-)
 delete mode 100644 drivers/cpufreq/exynos-cpufreq.c
 delete mode 100644 drivers/cpufreq/exynos-cpufreq.h
 delete mode 100644 drivers/cpufreq/exynos4210-cpufreq.c
 delete mode 100644 drivers/cpufreq/exynos4x12-cpufreq.c
 delete mode 100644 drivers/cpufreq/exynos5250-cpufreq.c

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 3129749..704656d 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -16,42 +16,6 @@ config ARM_DT_BL_CPUFREQ
 	  This enables probing via DT for Generic CPUfreq driver for ARM
 	  big.LITTLE platform. This gets frequency tables from DT.
 
-config ARM_EXYNOS_CPUFREQ
-	bool
-
-config ARM_EXYNOS4210_CPUFREQ
-	bool "SAMSUNG EXYNOS4210"
-	depends on CPU_EXYNOS4210
-	default y
-	select ARM_EXYNOS_CPUFREQ
-	help
-	  This adds the CPUFreq driver for Samsung EXYNOS4210
-	  SoC (S5PV310 or S5PC210).
-
-	  If in doubt, say N.
-
-config ARM_EXYNOS4X12_CPUFREQ
-	bool "SAMSUNG EXYNOS4x12"
-	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
-	default y
-	select ARM_EXYNOS_CPUFREQ
-	help
-	  This adds the CPUFreq driver for Samsung EXYNOS4X12
-	  SoC (EXYNOS4212 or EXYNOS4412).
-
-	  If in doubt, say N.
-
-config ARM_EXYNOS5250_CPUFREQ
-	bool "SAMSUNG EXYNOS5250"
-	depends on SOC_EXYNOS5250
-	default y
-	select ARM_EXYNOS_CPUFREQ
-	help
-	  This adds the CPUFreq driver for Samsung EXYNOS5250
-	  SoC.
-
-	  If in doubt, say N.
-
 config ARM_EXYNOS5440_CPUFREQ
 	bool "SAMSUNG EXYNOS5440"
 	depends on SOC_EXYNOS5440
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 7494565..3abfe05 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -49,10 +49,6 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ)		+= arm_big_little_dt.o
 
 obj-$(CONFIG_ARCH_DAVINCI_DA850)	+= davinci-cpufreq.o
 obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)	+= exynos-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ)	+= exynos5440-cpufreq.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)		+= imx6q-cpufreq.o
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
deleted file mode 100644
index fcd2914..0000000
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS - CPU frequency scaling support for EXYNOS series
- *
- * 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <linux/cpufreq.h>
-#include <linux/suspend.h>
-#include <linux/platform_device.h>
-
-#include <plat/cpu.h>
-
-#include "exynos-cpufreq.h"
-
-static struct exynos_dvfs_info *exynos_info;
-
-static struct regulator *arm_regulator;
-
-static unsigned int locking_frequency;
-static bool frequency_locked;
-static DEFINE_MUTEX(cpufreq_lock);
-
-static int exynos_cpufreq_get_index(unsigned int freq)
-{
-	struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
-	int index;
-
-	for (index = 0;
-		freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
-		if (freq_table[index].frequency == freq)
-			break;
-
-	if (freq_table[index].frequency == CPUFREQ_TABLE_END)
-		return -EINVAL;
-
-	return index;
-}
-
-static int exynos_cpufreq_scale(unsigned int target_freq)
-{
-	struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
-	unsigned int *volt_table = exynos_info->volt_table;
-	struct cpufreq_policy *policy = cpufreq_cpu_get(0);
-	unsigned int arm_volt, safe_arm_volt = 0;
-	unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
-	unsigned int old_freq;
-	int index, old_index;
-	int ret = 0;
-
-	old_freq = policy->cur;
-
-	/*
-	 * The policy max have been changed so that we cannot get proper
-	 * old_index with cpufreq_frequency_table_target(). Thus, ignore
-	 * policy and get the index from the raw frequency table.
-	 */
-	old_index = exynos_cpufreq_get_index(old_freq);
-	if (old_index < 0) {
-		ret = old_index;
-		goto out;
-	}
-
-	index = exynos_cpufreq_get_index(target_freq);
-	if (index < 0) {
-		ret = index;
-		goto out;
-	}
-
-	/*
-	 * ARM clock source will be changed APLL to MPLL temporary
-	 * To support this level, need to control regulator for
-	 * required voltage level
-	 */
-	if (exynos_info->need_apll_change != NULL) {
-		if (exynos_info->need_apll_change(old_index, index) &&
-		   (freq_table[index].frequency < mpll_freq_khz) &&
-		   (freq_table[old_index].frequency < mpll_freq_khz))
-			safe_arm_volt = volt_table[exynos_info->pll_safe_idx];
-	}
-	arm_volt = volt_table[index];
-
-	/* When the new frequency is higher than current frequency */
-	if ((target_freq > old_freq) && !safe_arm_volt) {
-		/* Firstly, voltage up to increase frequency */
-		ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
-		if (ret) {
-			pr_err("%s: failed to set cpu voltage to %d\n",
-				__func__, arm_volt);
-			return ret;
-		}
-	}
-
-	if (safe_arm_volt) {
-		ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
-				      safe_arm_volt);
-		if (ret) {
-			pr_err("%s: failed to set cpu voltage to %d\n",
-				__func__, safe_arm_volt);
-			return ret;
-		}
-	}
-
-	exynos_info->set_freq(old_index, index);
-
-	/* When the new frequency is lower than current frequency */
-	if ((target_freq < old_freq) ||
-	   ((target_freq > old_freq) && safe_arm_volt)) {
-		/* down the voltage after frequency change */
-		ret = regulator_set_voltage(arm_regulator, arm_volt,
-				arm_volt);
-		if (ret) {
-			pr_err("%s: failed to set cpu voltage to %d\n",
-				__func__, arm_volt);
-			goto out;
-		}
-	}
-
-out:
-	cpufreq_cpu_put(policy);
-
-	return ret;
-}
-
-static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
-{
-	struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
-	int ret = 0;
-
-	mutex_lock(&cpufreq_lock);
-
-	if (frequency_locked)
-		goto out;
-
-	ret = exynos_cpufreq_scale(freq_table[index].frequency);
-
-out:
-	mutex_unlock(&cpufreq_lock);
-
-	return ret;
-}
-
-#ifdef CONFIG_PM
-static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
-{
-	return 0;
-}
-
-static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
-{
-	return 0;
-}
-#endif
-
-/**
- * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
- *			context
- * @notifier
- * @pm_event
- * @v
- *
- * While frequency_locked == true, target() ignores every frequency but
- * locking_frequency. The locking_frequency value is the initial frequency,
- * which is set by the bootloader. In order to eliminate possible
- * inconsistency in clock values, we save and restore frequencies during
- * suspend and resume and block CPUFREQ activities. Note that the standard
- * suspend/resume cannot be used as they are too deep (syscore_ops) for
- * regulator actions.
- */
-static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
-				       unsigned long pm_event, void *v)
-{
-	int ret;
-
-	switch (pm_event) {
-	case PM_SUSPEND_PREPARE:
-		mutex_lock(&cpufreq_lock);
-		frequency_locked = true;
-		mutex_unlock(&cpufreq_lock);
-
-		ret = exynos_cpufreq_scale(locking_frequency);
-		if (ret < 0)
-			return NOTIFY_BAD;
-
-		break;
-
-	case PM_POST_SUSPEND:
-		mutex_lock(&cpufreq_lock);
-		frequency_locked = false;
-		mutex_unlock(&cpufreq_lock);
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block exynos_cpufreq_nb = {
-	.notifier_call = exynos_cpufreq_pm_notifier,
-};
-
-static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
-{
-	policy->clk = exynos_info->cpu_clk;
-	return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
-}
-
-static struct cpufreq_driver exynos_driver = {
-	.flags		= CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
-	.verify		= cpufreq_generic_frequency_table_verify,
-	.target_index	= exynos_target,
-	.get		= cpufreq_generic_get,
-	.init		= exynos_cpufreq_cpu_init,
-	.exit		= cpufreq_generic_exit,
-	.name		= "exynos_cpufreq",
-	.attr		= cpufreq_generic_attr,
-#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
-	.boost_supported = true,
-#endif
-#ifdef CONFIG_PM
-	.suspend	= exynos_cpufreq_suspend,
-	.resume		= exynos_cpufreq_resume,
-#endif
-};
-
-static int exynos_cpufreq_probe(struct platform_device *pdev)
-{
-	int ret = -EINVAL;
-
-	exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
-	if (!exynos_info)
-		return -ENOMEM;
-
-	if (soc_is_exynos4210())
-		ret = exynos4210_cpufreq_init(exynos_info);
-	else if (soc_is_exynos4212() || soc_is_exynos4412())
-		ret = exynos4x12_cpufreq_init(exynos_info);
-	else if (soc_is_exynos5250())
-		ret = exynos5250_cpufreq_init(exynos_info);
-	else
-		return 0;
-
-	if (ret)
-		goto err_vdd_arm;
-
-	if (exynos_info->set_freq == NULL) {
-		pr_err("%s: No set_freq function (ERR)\n", __func__);
-		goto err_vdd_arm;
-	}
-
-	arm_regulator = regulator_get(NULL, "vdd_arm");
-	if (IS_ERR(arm_regulator)) {
-		pr_err("%s: failed to get resource vdd_arm\n", __func__);
-		goto err_vdd_arm;
-	}
-
-	locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
-
-	register_pm_notifier(&exynos_cpufreq_nb);
-
-	if (cpufreq_register_driver(&exynos_driver)) {
-		pr_err("%s: failed to register cpufreq driver\n", __func__);
-		goto err_cpufreq;
-	}
-
-	return 0;
-err_cpufreq:
-	unregister_pm_notifier(&exynos_cpufreq_nb);
-
-	regulator_put(arm_regulator);
-err_vdd_arm:
-	kfree(exynos_info);
-	return -EINVAL;
-}
-
-static struct platform_driver exynos_cpufreq_platdrv = {
-	.driver = {
-		.name	= "exynos-cpufreq",
-		.owner	= THIS_MODULE,
-	},
-	.probe = exynos_cpufreq_probe,
-};
-module_platform_driver(exynos_cpufreq_platdrv);
diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h
deleted file mode 100644
index 3ddade8..0000000
--- a/drivers/cpufreq/exynos-cpufreq.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS - CPUFreq 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.
-*/
-
-enum cpufreq_level_index {
-	L0, L1, L2, L3, L4,
-	L5, L6, L7, L8, L9,
-	L10, L11, L12, L13, L14,
-	L15, L16, L17, L18, L19,
-	L20,
-};
-
-#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m, p, s) \
-	{ \
-		.freq = (f) * 1000, \
-		.clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3) << 12 | \
-			(a4) << 16 | (a5) << 20 | (a6) << 24 | (a7) << 28), \
-		.clk_div_cpu1 = (b0 << 0 | b1 << 4 | b2 << 8), \
-		.mps = ((m) << 16 | (p) << 8 | (s)), \
-	}
-
-struct apll_freq {
-	unsigned int freq;
-	u32 clk_div_cpu0;
-	u32 clk_div_cpu1;
-	u32 mps;
-};
-
-struct exynos_dvfs_info {
-	unsigned long	mpll_freq_khz;
-	unsigned int	pll_safe_idx;
-	struct clk	*cpu_clk;
-	unsigned int	*volt_table;
-	struct cpufreq_frequency_table	*freq_table;
-	void (*set_freq)(unsigned int, unsigned int);
-	bool (*need_apll_change)(unsigned int, unsigned int);
-};
-
-#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
-extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
-#else
-static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
-{
-	return -EOPNOTSUPP;
-}
-#endif
-#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
-extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
-#else
-static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
-{
-	return -EOPNOTSUPP;
-}
-#endif
-#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
-extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
-#else
-static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
-{
-	return -EOPNOTSUPP;
-}
-#endif
-
-#include <plat/cpu.h>
-#include <mach/map.h>
-
-#define EXYNOS4_CLKSRC_CPU			(S5P_VA_CMU + 0x14200)
-#define EXYNOS4_CLKMUX_STATCPU			(S5P_VA_CMU + 0x14400)
-
-#define EXYNOS4_CLKDIV_CPU			(S5P_VA_CMU + 0x14500)
-#define EXYNOS4_CLKDIV_CPU1			(S5P_VA_CMU + 0x14504)
-#define EXYNOS4_CLKDIV_STATCPU			(S5P_VA_CMU + 0x14600)
-#define EXYNOS4_CLKDIV_STATCPU1			(S5P_VA_CMU + 0x14604)
-
-#define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT	(16)
-#define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK	(0x7 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)
-
-#define EXYNOS5_APLL_LOCK			(S5P_VA_CMU + 0x00000)
-#define EXYNOS5_APLL_CON0			(S5P_VA_CMU + 0x00100)
-#define EXYNOS5_CLKMUX_STATCPU			(S5P_VA_CMU + 0x00400)
-#define EXYNOS5_CLKDIV_CPU0			(S5P_VA_CMU + 0x00500)
-#define EXYNOS5_CLKDIV_CPU1			(S5P_VA_CMU + 0x00504)
-#define EXYNOS5_CLKDIV_STATCPU0			(S5P_VA_CMU + 0x00600)
-#define EXYNOS5_CLKDIV_STATCPU1			(S5P_VA_CMU + 0x00604)
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
deleted file mode 100644
index 40d84c4..0000000
--- a/drivers/cpufreq/exynos4210-cpufreq.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS4210 - CPU frequency scaling 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.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/cpufreq.h>
-
-#include "exynos-cpufreq.h"
-
-static struct clk *cpu_clk;
-static struct clk *moutcore;
-static struct clk *mout_mpll;
-static struct clk *mout_apll;
-
-static unsigned int exynos4210_volt_table[] = {
-	1250000, 1150000, 1050000, 975000, 950000,
-};
-
-static struct cpufreq_frequency_table exynos4210_freq_table[] = {
-	{L0, 1200 * 1000},
-	{L1, 1000 * 1000},
-	{L2,  800 * 1000},
-	{L3,  500 * 1000},
-	{L4,  200 * 1000},
-	{0, CPUFREQ_TABLE_END},
-};
-
-static struct apll_freq apll_freq_4210[] = {
-	/*
-	 * values:
-	 * freq
-	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, RESERVED
-	 * clock divider for COPY, HPM, RESERVED
-	 * PLL M, P, S
-	 */
-	APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
-	APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
-	APLL_FREQ(800,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
-	APLL_FREQ(500,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
-	APLL_FREQ(200,  0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
-};
-
-static void exynos4210_set_clkdiv(unsigned int div_index)
-{
-	unsigned int tmp;
-
-	/* Change Divider - CPU0 */
-
-	tmp = apll_freq_4210[div_index].clk_div_cpu0;
-
-	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
-
-	do {
-		tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
-	} while (tmp & 0x1111111);
-
-	/* Change Divider - CPU1 */
-
-	tmp = apll_freq_4210[div_index].clk_div_cpu1;
-
-	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
-
-	do {
-		tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
-	} while (tmp & 0x11);
-}
-
-static void exynos4210_set_apll(unsigned int index)
-{
-	unsigned int tmp, freq = apll_freq_4210[index].freq;
-
-	/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
-	clk_set_parent(moutcore, mout_mpll);
-
-	do {
-		tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
-			>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
-		tmp &= 0x7;
-	} while (tmp != 0x2);
-
-	clk_set_rate(mout_apll, freq * 1000);
-
-	/* MUX_CORE_SEL = APLL */
-	clk_set_parent(moutcore, mout_apll);
-
-	do {
-		tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
-		tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
-	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
-}
-
-static void exynos4210_set_frequency(unsigned int old_index,
-				     unsigned int new_index)
-{
-	if (old_index > new_index) {
-		exynos4210_set_clkdiv(new_index);
-		exynos4210_set_apll(new_index);
-	} else if (old_index < new_index) {
-		exynos4210_set_apll(new_index);
-		exynos4210_set_clkdiv(new_index);
-	}
-}
-
-int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
-{
-	unsigned long rate;
-
-	cpu_clk = clk_get(NULL, "armclk");
-	if (IS_ERR(cpu_clk))
-		return PTR_ERR(cpu_clk);
-
-	moutcore = clk_get(NULL, "moutcore");
-	if (IS_ERR(moutcore))
-		goto err_moutcore;
-
-	mout_mpll = clk_get(NULL, "mout_mpll");
-	if (IS_ERR(mout_mpll))
-		goto err_mout_mpll;
-
-	rate = clk_get_rate(mout_mpll) / 1000;
-
-	mout_apll = clk_get(NULL, "mout_apll");
-	if (IS_ERR(mout_apll))
-		goto err_mout_apll;
-
-	info->mpll_freq_khz = rate;
-	/* 800Mhz */
-	info->pll_safe_idx = L2;
-	info->cpu_clk = cpu_clk;
-	info->volt_table = exynos4210_volt_table;
-	info->freq_table = exynos4210_freq_table;
-	info->set_freq = exynos4210_set_frequency;
-
-	return 0;
-
-err_mout_apll:
-	clk_put(mout_mpll);
-err_mout_mpll:
-	clk_put(moutcore);
-err_moutcore:
-	clk_put(cpu_clk);
-
-	pr_debug("%s: failed initialization\n", __func__);
-	return -EINVAL;
-}
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
deleted file mode 100644
index 7c11ace..0000000
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS4X12 - CPU frequency scaling 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.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/cpufreq.h>
-
-#include "exynos-cpufreq.h"
-
-static struct clk *cpu_clk;
-static struct clk *moutcore;
-static struct clk *mout_mpll;
-static struct clk *mout_apll;
-
-static unsigned int exynos4x12_volt_table[] = {
-	1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
-	1000000,  987500,  975000,  950000,  925000,  900000,  900000
-};
-
-static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
-	{CPUFREQ_BOOST_FREQ, 1500 * 1000},
-	{L1, 1400 * 1000},
-	{L2, 1300 * 1000},
-	{L3, 1200 * 1000},
-	{L4, 1100 * 1000},
-	{L5, 1000 * 1000},
-	{L6,  900 * 1000},
-	{L7,  800 * 1000},
-	{L8,  700 * 1000},
-	{L9,  600 * 1000},
-	{L10, 500 * 1000},
-	{L11, 400 * 1000},
-	{L12, 300 * 1000},
-	{L13, 200 * 1000},
-	{0, CPUFREQ_TABLE_END},
-};
-
-static struct apll_freq *apll_freq_4x12;
-
-static struct apll_freq apll_freq_4212[] = {
-	/*
-	 * values:
-	 * freq
-	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
-	 * clock divider for COPY, HPM, RESERVED
-	 * PLL M, P, S
-	 */
-	APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
-	APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
-	APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
-	APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
-	APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
-	APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
-	APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
-	APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
-	APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
-	APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
-	APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
-	APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
-	APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
-	APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
-};
-
-static struct apll_freq apll_freq_4412[] = {
-	/*
-	 * values:
-	 * freq
-	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
-	 * clock divider for COPY, HPM, CORES
-	 * PLL M, P, S
-	 */
-	APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
-	APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
-	APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
-	APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
-	APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
-	APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
-	APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
-	APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
-	APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
-	APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
-	APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
-	APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
-	APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
-	APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
-};
-
-static void exynos4x12_set_clkdiv(unsigned int div_index)
-{
-	unsigned int tmp;
-	unsigned int stat_cpu1;
-
-	/* Change Divider - CPU0 */
-
-	tmp = apll_freq_4x12[div_index].clk_div_cpu0;
-
-	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
-
-	while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
-		cpu_relax();
-
-	/* Change Divider - CPU1 */
-	tmp = apll_freq_4x12[div_index].clk_div_cpu1;
-
-	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
-	if (soc_is_exynos4212())
-		stat_cpu1 = 0x11;
-	else
-		stat_cpu1 = 0x111;
-
-	while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
-		cpu_relax();
-}
-
-static void exynos4x12_set_apll(unsigned int index)
-{
-	unsigned int tmp, freq = apll_freq_4x12[index].freq;
-
-	/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
-	clk_set_parent(moutcore, mout_mpll);
-
-	do {
-		cpu_relax();
-		tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
-			>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
-		tmp &= 0x7;
-	} while (tmp != 0x2);
-
-	clk_set_rate(mout_apll, freq * 1000);
-
-	/* MUX_CORE_SEL = APLL */
-	clk_set_parent(moutcore, mout_apll);
-
-	do {
-		cpu_relax();
-		tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
-		tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
-	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
-}
-
-static void exynos4x12_set_frequency(unsigned int old_index,
-				  unsigned int new_index)
-{
-	if (old_index > new_index) {
-		exynos4x12_set_clkdiv(new_index);
-		exynos4x12_set_apll(new_index);
-	} else if (old_index < new_index) {
-		exynos4x12_set_apll(new_index);
-		exynos4x12_set_clkdiv(new_index);
-	}
-}
-
-int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
-{
-	unsigned long rate;
-
-	cpu_clk = clk_get(NULL, "armclk");
-	if (IS_ERR(cpu_clk))
-		return PTR_ERR(cpu_clk);
-
-	moutcore = clk_get(NULL, "moutcore");
-	if (IS_ERR(moutcore))
-		goto err_moutcore;
-
-	mout_mpll = clk_get(NULL, "mout_mpll");
-	if (IS_ERR(mout_mpll))
-		goto err_mout_mpll;
-
-	rate = clk_get_rate(mout_mpll) / 1000;
-
-	mout_apll = clk_get(NULL, "mout_apll");
-	if (IS_ERR(mout_apll))
-		goto err_mout_apll;
-
-	if (soc_is_exynos4212())
-		apll_freq_4x12 = apll_freq_4212;
-	else
-		apll_freq_4x12 = apll_freq_4412;
-
-	info->mpll_freq_khz = rate;
-	/* 800Mhz */
-	info->pll_safe_idx = L7;
-	info->cpu_clk = cpu_clk;
-	info->volt_table = exynos4x12_volt_table;
-	info->freq_table = exynos4x12_freq_table;
-	info->set_freq = exynos4x12_set_frequency;
-
-	return 0;
-
-err_mout_apll:
-	clk_put(mout_mpll);
-err_mout_mpll:
-	clk_put(moutcore);
-err_moutcore:
-	clk_put(cpu_clk);
-
-	pr_debug("%s: failed initialization\n", __func__);
-	return -EINVAL;
-}
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
deleted file mode 100644
index 5f90b82..0000000
--- a/drivers/cpufreq/exynos5250-cpufreq.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * EXYNOS5250 - CPU frequency scaling 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.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/cpufreq.h>
-
-#include <mach/map.h>
-
-#include "exynos-cpufreq.h"
-
-static struct clk *cpu_clk;
-static struct clk *moutcore;
-static struct clk *mout_mpll;
-static struct clk *mout_apll;
-
-static unsigned int exynos5250_volt_table[] = {
-	1300000, 1250000, 1225000, 1200000, 1150000,
-	1125000, 1100000, 1075000, 1050000, 1025000,
-	1012500, 1000000,  975000,  950000,  937500,
-	925000
-};
-
-static struct cpufreq_frequency_table exynos5250_freq_table[] = {
-	{L0, 1700 * 1000},
-	{L1, 1600 * 1000},
-	{L2, 1500 * 1000},
-	{L3, 1400 * 1000},
-	{L4, 1300 * 1000},
-	{L5, 1200 * 1000},
-	{L6, 1100 * 1000},
-	{L7, 1000 * 1000},
-	{L8,  900 * 1000},
-	{L9,  800 * 1000},
-	{L10, 700 * 1000},
-	{L11, 600 * 1000},
-	{L12, 500 * 1000},
-	{L13, 400 * 1000},
-	{L14, 300 * 1000},
-	{L15, 200 * 1000},
-	{0, CPUFREQ_TABLE_END},
-};
-
-static struct apll_freq apll_freq_5250[] = {
-	/*
-	 * values:
-	 * freq
-	 * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2
-	 * clock divider for COPY, HPM, RESERVED
-	 * PLL M, P, S
-	 */
-	APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
-	APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
-	APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
-	APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
-	APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
-	APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
-	APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
-	APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
-	APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
-	APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
-	APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
-	APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
-	APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
-	APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
-	APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
-	APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
-};
-
-static void set_clkdiv(unsigned int div_index)
-{
-	unsigned int tmp;
-
-	/* Change Divider - CPU0 */
-
-	tmp = apll_freq_5250[div_index].clk_div_cpu0;
-
-	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
-
-	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
-		cpu_relax();
-
-	/* Change Divider - CPU1 */
-	tmp = apll_freq_5250[div_index].clk_div_cpu1;
-
-	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
-
-	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
-		cpu_relax();
-}
-
-static void set_apll(unsigned int index)
-{
-	unsigned int tmp;
-	unsigned int freq = apll_freq_5250[index].freq;
-
-	/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
-	clk_set_parent(moutcore, mout_mpll);
-
-	do {
-		cpu_relax();
-		tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
-		tmp &= 0x7;
-	} while (tmp != 0x2);
-
-	clk_set_rate(mout_apll, freq * 1000);
-
-	/* MUX_CORE_SEL = APLL */
-	clk_set_parent(moutcore, mout_apll);
-
-	do {
-		cpu_relax();
-		tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
-		tmp &= (0x7 << 16);
-	} while (tmp != (0x1 << 16));
-}
-
-static void exynos5250_set_frequency(unsigned int old_index,
-				  unsigned int new_index)
-{
-	if (old_index > new_index) {
-		set_clkdiv(new_index);
-		set_apll(new_index);
-	} else if (old_index < new_index) {
-		set_apll(new_index);
-		set_clkdiv(new_index);
-	}
-}
-
-int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
-{
-	unsigned long rate;
-
-	cpu_clk = clk_get(NULL, "armclk");
-	if (IS_ERR(cpu_clk))
-		return PTR_ERR(cpu_clk);
-
-	moutcore = clk_get(NULL, "mout_cpu");
-	if (IS_ERR(moutcore))
-		goto err_moutcore;
-
-	mout_mpll = clk_get(NULL, "mout_mpll");
-	if (IS_ERR(mout_mpll))
-		goto err_mout_mpll;
-
-	rate = clk_get_rate(mout_mpll) / 1000;
-
-	mout_apll = clk_get(NULL, "mout_apll");
-	if (IS_ERR(mout_apll))
-		goto err_mout_apll;
-
-	info->mpll_freq_khz = rate;
-	/* 800Mhz */
-	info->pll_safe_idx = L9;
-	info->cpu_clk = cpu_clk;
-	info->volt_table = exynos5250_volt_table;
-	info->freq_table = exynos5250_freq_table;
-	info->set_freq = exynos5250_set_frequency;
-
-	return 0;
-
-err_mout_apll:
-	clk_put(mout_mpll);
-err_mout_mpll:
-	clk_put(moutcore);
-err_moutcore:
-	clk_put(cpu_clk);
-
-	pr_err("%s: failed initialization\n", __func__);
-	return -EINVAL;
-}
-- 
1.6.6.rc2

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

* [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5
  2014-01-18 12:10 ` [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5 Thomas Abraham
@ 2014-01-18 15:22   ` Rob Herring
  2014-01-21  7:31     ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Rob Herring @ 2014-01-18 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jan 18, 2014 at 6:10 AM, Thomas Abraham <ta.omasab@gmail.com> wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
>
> The clk ops of the new Samsung cpu clock provider type requires configuration
> data that will be programmed in the multiple clock blocks encapsulated within
> the cpu clock provider type. This configuration data is held in the clock
> controller node. Update clock binding documentation about this configuration
> data format for Samsung Exynos4 and Exynos5 platforms.
>
> Cc: Rob Herring <robh+dt@kernel.org>

Please copy all maintainers.

> Cc: Tomasz Figa <t.figa@samsung.com>
> Cc: <devicetree@vger.kernel.org>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  .../devicetree/bindings/clock/exynos4-clock.txt    |   30 ++++++++++++++++++++
>  .../devicetree/bindings/clock/exynos5250-clock.txt |   21 ++++++++++++++
>  2 files changed, 51 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
> index a2ac2d9..c28aabd 100644
> --- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
> +++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
> @@ -15,6 +15,29 @@ Required Properties:
>
>  - #clock-cells: should be 1.
>
> +- arm-frequency-table: defines the list of arm clock speeds supported and

Seems like a Samsung specific property and nothing to do with ARM, so
it should be named accordingly.

> +  the associated configuration values required to setup the clock controller
> +  for generating those speeds. The format of each entry included in the
> +  arm-frequency-table should be as defined below (#cells per entry = 13)
> +
> +  - for Exynos4210 and Exynos4212 based platforms:
> +      cell #1: arm clock frequency
> +      cell #2: expected arm clock parent frequency
> +      cell #3 ~ cell 12#: value of clock divider in the following order
> +              core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
> +              atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
> +              copy_ratio, hpm_ratio.
> +      cell #13: reserved (should be zero).
> +
> +  - for Exynos4412 based platforms:
> +      cell #1: arm clock frequency
> +      cell #2: expected arm clock parent frequency
> +      cell #3 ~ cell #13: value of clock divider in the following order
> +              core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
> +              atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
> +              copy_ratio, hpm_ratio, cores_ratio

You don't need voltages? Are the h/w limitations really ratios or each
clock has a max frequency that must be maintained? I would expect the
latter and think it would be better to specify maximum frequencies of
each clock. Then you can calculate the dividers to keep frequencies in
range.

How will this scale to multi-cluster chips with different frequency ranges?

Rob

> +
> +
>  The following is the list of clocks generated by the controller. Each clock is
>  assigned an identifier and client nodes use this identifier to specify the
>  clock which they consume. Some of the clocks are available only on a particular
> @@ -275,6 +298,13 @@ Example 1: An example of a clock controller node is listed below.
>                 compatible = "samsung,exynos4210-clock";
>                 reg = <0x10030000 0x20000>;
>                 #clock-cells = <1>;
> +
> +               arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7 0 5 0>,
> +                                     <1000000 1000000 0 3 7 3 4 1 7 0 4 0>,
> +                                     < 800000  800000 0 3 7 3 3 1 7 0 3 0>,
> +                                     < 500000  500000 0 3 7 3 3 1 7 0 3 0>,
> +                                     < 400000  400000 0 3 7 3 3 1 7 0 3 0>,
> +                                     < 200000  200000 0 1 3 1 1 1 0 0 3 0>;
>         };
>
>  Example 2: UART controller node that consumes the clock generated by the clock
> diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> index 72ce617..99eae9c 100644
> --- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> +++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> @@ -13,6 +13,20 @@ Required Properties:
>
>  - #clock-cells: should be 1.
>
> +- arm-frequency-table: defines the list of arm clock speeds supported and
> +  the associated configuration values required to setup the clock controller
> +  for generating those speeds. The format of each entry included in the
> +  arm-frequency-table should be as defined below (#cells per entry = 13)
> +
> +      cell #1: arm clock frequency
> +      cell #2: expected arm clock parent frequency
> +      cell #3 ~ cell #12: value of clock divider in the following order
> +              arm_ratio, cpud_ratio, acp_ratio, periph_ratio,
> +              atb_ratio, pclk_dbg_ratio, apll_ratio, arm2_ratio,
> +              copy_ratio, hpm_ratio
> +      cell #13: reserved (should be zero)
> +
> +
>  The following is the list of clocks generated by the controller. Each clock is
>  assigned an identifier and client nodes use this identifier to specify the
>  clock which they consume.
> @@ -177,6 +191,13 @@ Example 1: An example of a clock controller node is listed below.
>                 compatible = "samsung,exynos5250-clock";
>                 reg = <0x10010000 0x30000>;
>                 #clock-cells = <1>;
> +
> +               arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5 0 0 2>,
> +                                     <1600000 1600000 0 3 7 7 7 1 4 0 0 2>,
> +                                     <1500000 1500000 0 2 7 7 7 1 4 0 0 2>,
> +                                     <1400000 1400000 0 2 7 7 6 1 4 0 0 2>,
> +                                     <1300000 1300000 0 2 7 7 6 1 3 0 0 2>,
> +                                     <1200000 1200000 0 2 7 7 5 1 3 0 0 2>;
>         };
>
>  Example 2: UART controller node that consumes the clock generated by the clock
> --
> 1.6.6.rc2
>

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

* [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table
  2014-01-18 12:10 ` [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table Thomas Abraham
@ 2014-01-20  7:32   ` Lukasz Majewski
  2014-01-21  7:33     ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-20  7:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> For all Exynos based platforms, add CPU nodes, operating points and
> cpu clock frequency table for migrating from Exynos specific cpufreq
> driver to using generic cpufreq-cpu0 driver.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  arch/arm/boot/dts/exynos4210-origen.dts         |    6 +++
>  arch/arm/boot/dts/exynos4210-trats.dts          |    6 +++
>  arch/arm/boot/dts/exynos4210-universal_c210.dts |    6 +++
>  arch/arm/boot/dts/exynos4210.dtsi               |   35
> ++++++++++++++++++ arch/arm/boot/dts/exynos4212.dtsi
> |   17 +++++++++ arch/arm/boot/dts/exynos4412-odroidx.dts        |
> 6 +++ arch/arm/boot/dts/exynos4412-origen.dts         |    6 +++
>  arch/arm/boot/dts/exynos4412-trats2.dts         |    6 +++
>  arch/arm/boot/dts/exynos4412.dtsi               |   30
> ++++++++++++++++ arch/arm/boot/dts/exynos4x12.dtsi               |
> 35 ++++++++++++++++++ arch/arm/boot/dts/exynos5250-arndale.dts
> |    6 +++ arch/arm/boot/dts/exynos5250-cros-common.dtsi   |    6 +++
>  arch/arm/boot/dts/exynos5250-smdk5250.dts       |    6 +++
>  arch/arm/boot/dts/exynos5250.dtsi               |   43
> ++++++++++++++++++++++- 14 files changed, 213 insertions(+), 1
> deletions(-)
> 
> diff --git a/arch/arm/boot/dts/exynos4210-origen.dts
> b/arch/arm/boot/dts/exynos4210-origen.dts index 2aa13cb..dd17e93
> 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts
> +++ b/arch/arm/boot/dts/exynos4210-origen.dts
> @@ -32,6 +32,12 @@
>  		bootargs ="root=/dev/ram0 rw ramdisk=8192
> initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; };
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck1_reg>;
> +		};
> +	};
> +
>  	regulators {
>  		compatible = "simple-bus";
>  		#address-cells = <1>;
> diff --git a/arch/arm/boot/dts/exynos4210-trats.dts
> b/arch/arm/boot/dts/exynos4210-trats.dts index 63cc571..25487d7 100644
> --- a/arch/arm/boot/dts/exynos4210-trats.dts
> +++ b/arch/arm/boot/dts/exynos4210-trats.dts
> @@ -30,6 +30,12 @@
>  		bootargs = "console=ttySAC2,115200N8
> root=/dev/mmcblk0p5 rootwait earlyprintk panic=5"; };
>  
> +	cpus {
> +		cpu: cpu at 0 {
> +			cpu0-supply = <&varm_breg>;
> +		};
> +	};
> +
>  	regulators {
>  		compatible = "simple-bus";
>  
> diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts
> b/arch/arm/boot/dts/exynos4210-universal_c210.dts index
> d2e3f5f..74d5a70 100644 ---
> a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++
> b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -28,6 +28,12 @@
>  		bootargs = "console=ttySAC2,115200N8
> root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1"; };
>  
> +	cpus {
> +		cpu: cpu at 0 {
> +			cpu0-supply = <&vdd_arm_reg>;
> +		};
> +	};
> +
>  	mct at 10050000 {
>  		compatible = "none";
>  	};
> diff --git a/arch/arm/boot/dts/exynos4210.dtsi
> b/arch/arm/boot/dts/exynos4210.dtsi index 48ecd7a..40cd663 100644
> --- a/arch/arm/boot/dts/exynos4210.dtsi
> +++ b/arch/arm/boot/dts/exynos4210.dtsi
> @@ -36,6 +36,34 @@
>  		reg = <0x10023CA0 0x20>;
>  	};
>  
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		cpu at 0 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a9";
> +			reg = <0>;
> +			clocks = <&clock 12>;
> +			clock-names = "cpu";
> +
> +			operating-points = <
> +				200000	950000
> +				400000	975000
> +				500000	975000
> +				800000	1075000
> +				1000000	1150000
> +				1200000	1250000

Please be consistent with "operating-points" definition. Here you use
increasing order, when below you use decreasing one.

> +			>;
> +			safe-opp = <800000 1075000>;
> +		};
> +
> +		cpu at 1 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a9";
> +			reg = <1>;
> +		};
> +	};
> +
>  	gic: interrupt-controller at 10490000 {
>  		cpu-offset = <0x8000>;
>  	};
> @@ -73,6 +101,13 @@
>  		compatible = "samsung,exynos4210-clock";
>  		reg = <0x10030000 0x20000>;
>  		#clock-cells = <1>;
> +
> +		arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7
> 0 5 0 0>,
> +				      <1000000 1000000 0 3 7 3 4 1 7
> 0 4 0 0>,
> +				      < 800000  800000 0 3 7 3 3 1 7
> 0 3 0 0>,
> +				      < 500000  500000 0 3 7 3 3 1 7
> 0 3 0 0>,
> +				      < 400000  400000 0 3 7 3 3 1 7
> 0 3 0 0>,
> +				      < 200000  200000 0 1 3 1 1 1 0
> 0 3 0 0>; };
>  
>  	pmu {
> diff --git a/arch/arm/boot/dts/exynos4212.dtsi
> b/arch/arm/boot/dts/exynos4212.dtsi index 94a43f9..2ea0f83 100644
> --- a/arch/arm/boot/dts/exynos4212.dtsi
> +++ b/arch/arm/boot/dts/exynos4212.dtsi
> @@ -22,6 +22,23 @@
>  / {
>  	compatible = "samsung,exynos4212";
>  
> +	clock: clock-controller at 10030000 {
> +		arm-frequency-table = <1500000 1500000 0 3 7 0 6 1 2
> 0 6 2 0>,
> +				      <1400000 1400000 0 3 7 0 6 1 2
> 0 6 2 0>,
> +				      <1300000 1300000 0 3 7 0 5 1 2
> 0 5 2 0>,
> +				      <1200000 1200000 0 3 7 0 5 1 2
> 0 5 2 0>,
> +				      <1100000 1100000 0 3 6 0 4 1 2
> 0 4 2 0>,
> +				      <1000000 1000000 0 2 5 0 4 1 1
> 0 4 2 0>,
> +				      < 900000  900000 0 2 5 0 3 1 1
> 0 3 2 0>,
> +				      < 800000  800000 0 2 5 0 3 1 1
> 0 3 2 0>,
> +				      < 700000  700000 0 2 4 0 3 1 1
> 0 3 2 0>,
> +				      < 600000  600000 0 2 4 0 3 1 1
> 0 3 2 0>,
> +				      < 500000  500000 0 2 4 0 3 1 1
> 0 3 2 0>,
> +				      < 400000  400000 0 2 4 0 3 1 1
> 0 3 2 0>,
> +				      < 300000  300000 0 2 4 0 2 1 1
> 0 3 2 0>,
> +				      < 200000  200000 0 1 3 0 1 1 1
> 0 3 2 0>;
> +	};
> +
>  	gic: interrupt-controller at 10490000 {
>  		cpu-offset = <0x8000>;
>  	};
> diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts
> b/arch/arm/boot/dts/exynos4412-odroidx.dts index 12459b0..1c751f9
> 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx.dts
> +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts
> @@ -22,6 +22,12 @@
>  		reg = <0x40000000 0x40000000>;
>  	};
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck2_reg>;
> +		};
> +	};
> +
>  	leds {
>  		compatible = "gpio-leds";
>  		led1 {
> diff --git a/arch/arm/boot/dts/exynos4412-origen.dts
> b/arch/arm/boot/dts/exynos4412-origen.dts index 388f035..36080e5
> 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts
> +++ b/arch/arm/boot/dts/exynos4412-origen.dts
> @@ -27,6 +27,12 @@
>  		bootargs ="console=ttySAC2,115200";
>  	};
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck2_reg>;
> +		};
> +	};
> +
>  	firmware at 0203F000 {
>  		compatible = "samsung,secure-firmware";
>  		reg = <0x0203F000 0x1000>;
> diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts
> b/arch/arm/boot/dts/exynos4412-trats2.dts index 4f851cc..4a4d446
> 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts
> +++ b/arch/arm/boot/dts/exynos4412-trats2.dts
> @@ -31,6 +31,12 @@
>  		bootargs = "console=ttySAC2,115200N8
> root=/dev/mmcblk0p5 rootwait earlyprintk panic=5"; };
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck2_reg>;
> +		};
> +	};
> +
>  	firmware at 0204F000 {
>  		compatible = "samsung,secure-firmware";
>  		reg = <0x0204F000 0x1000>;
> diff --git a/arch/arm/boot/dts/exynos4412.dtsi
> b/arch/arm/boot/dts/exynos4412.dtsi index 87b339c..7e9eca7 100644
> --- a/arch/arm/boot/dts/exynos4412.dtsi
> +++ b/arch/arm/boot/dts/exynos4412.dtsi
> @@ -22,6 +22,36 @@
>  / {
>  	compatible = "samsung,exynos4412";
>  
> +	cpus {
> +		cpu at 2 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a9";
> +			reg = <2>;
> +		};
> +		cpu at 3 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a9";
> +			reg = <3>;
> +		};
> +	};
> +
> +	clock: clock-controller at 10030000 {
> +		arm-frequency-table = <1500000 1500000 0 3 7 0 6 1 2
> 0 6 0 7>,
> +				      <1400000 1400000 0 3 7 0 6 1 2
> 0 6 0 6>,
> +				      <1300000 1300000 0 3 7 0 5 1 2
> 0 5 0 6>,
> +				      <1200000 1200000 0 3 7 0 5 1 2
> 0 5 0 5>,
> +				      <1100000 1100000 0 3 6 0 4 1 2
> 0 4 0 5>,
> +				      <1000000 1000000 0 2 5 0 4 1 1
> 0 4 0 4>,
> +				      < 900000  900000 0 2 5 0 3 1 1
> 0 3 0 4>,
> +				      < 800000  800000 0 2 5 0 3 1 1
> 0 3 0 3>,
> +				      < 700000  700000 0 2 4 0 3 1 1
> 0 3 0 3>,
> +				      < 600000  600000 0 2 4 0 3 1 1
> 0 3 0 2>,
> +				      < 500000  500000 0 2 4 0 3 1 1
> 0 3 0 2>,
> +				      < 400000  400000 0 2 4 0 3 1 1
> 0 3 0 1>,
> +				      < 300000  300000 0 2 4 0 2 1 1
> 0 3 0 1>,
> +				      < 200000  200000 0 1 3 0 1 1 1
> 0 3 0 0>;
> +	};
> +
>  	gic: interrupt-controller at 10490000 {
>  		cpu-offset = <0x4000>;
>  	};
> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi
> b/arch/arm/boot/dts/exynos4x12.dtsi index 5c412aa..47e2195 100644
> --- a/arch/arm/boot/dts/exynos4x12.dtsi
> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
> @@ -31,6 +31,41 @@
>  		mshc0 = &mshc_0;
>  	};
>  
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		cpu at 0 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a9";
> +			reg = <0>;
> +			clocks = <&clock 12>;
> +			clock-names = "cpu";
> +
> +			operating-points = <
> +				1400000 1350000
> +				1300000 1287500
> +				1200000 1250000
> +				1100000 1187500
> +				1000000 1137500
> +				 900000 1087500
> +				 800000 1037500
> +				 700000 1000000
> +				 600000  987500
> +				 500000  950000
> +				 400000  925000
> +				 300000  900000
> +				 200000  900000
> +			>;
> +			clock-latency = <200000>;
> +			safe-opp = <800000 1037500>;
> +		};
> +		cpu at 1 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a9";
> +			reg = <1>;
> +		};
> +	};
> +
>  	pd_isp: isp-power-domain at 10023CA0 {
>  		compatible = "samsung,exynos4210-pd";
>  		reg = <0x10023CA0 0x20>;
> diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts
> b/arch/arm/boot/dts/exynos5250-arndale.dts index b42e658..4716eef
> 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts
> +++ b/arch/arm/boot/dts/exynos5250-arndale.dts
> @@ -25,6 +25,12 @@
>  		bootargs = "console=ttySAC2,115200";
>  	};
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck2_reg>;
> +		};
> +	};
> +
>  	codec at 11000000 {
>  		samsung,mfc-r = <0x43000000 0x800000>;
>  		samsung,mfc-l = <0x51000000 0x800000>;
> diff --git a/arch/arm/boot/dts/exynos5250-cros-common.dtsi
> b/arch/arm/boot/dts/exynos5250-cros-common.dtsi index
> 2c1560d..4bde756 100644 ---
> a/arch/arm/boot/dts/exynos5250-cros-common.dtsi +++
> b/arch/arm/boot/dts/exynos5250-cros-common.dtsi @@ -19,6 +19,12 @@
>  	chosen {
>  	};
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck2_reg>;
> +		};
> +	};
> +
>  	pinctrl at 11400000 {
>  		/*
>  		 * Disabled pullups since external part has its own
> pullups and diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts
> b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 5c1b7d9..7c228e2
> 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
> +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
> @@ -27,6 +27,12 @@
>  		bootargs = "root=/dev/ram0 rw ramdisk=8192
> initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; };
>  
> +	cpus {
> +		cpu at 0 {
> +			cpu0-supply = <&buck2_reg>;
> +		};
> +	};
> +
>  	i2c at 12C60000 {
>  		samsung,i2c-sda-delay = <100>;
>  		samsung,i2c-max-bus-freq = <20000>;
> diff --git a/arch/arm/boot/dts/exynos5250.dtsi
> b/arch/arm/boot/dts/exynos5250.dtsi index b7dec41..d2f98dc 100644
> --- a/arch/arm/boot/dts/exynos5250.dtsi
> +++ b/arch/arm/boot/dts/exynos5250.dtsi
> @@ -61,6 +61,30 @@
>  			compatible = "arm,cortex-a15";
>  			reg = <0>;
>  			clock-frequency = <1700000000>;
> +
> +			clocks = <&clock 12>;
> +			clock-names = "cpu";
> +
> +			operating-points = <
> +				1700000 1300000
> +				1600000 1250000
> +				1500000 1225000
> +				1400000 1200000
> +				1300000 1150000
> +				1200000 1125000
> +				1100000 1100000
> +				1000000 1075000
> +				 900000 1050000
> +				 800000 1025000
> +				 700000 1012500
> +				 600000 1000000
> +				 500000  975000
> +				 400000  950000
> +				 300000  937500
> +				 200000  925000
> +			>;
> +			clock-latency = <200000>;
> +			safe-opp = <800000 1025000>;
>  		};
>  		cpu at 1 {
>  			device_type = "cpu";
> @@ -84,7 +108,24 @@
>  		compatible = "samsung,exynos5250-clock";
>  		reg = <0x10010000 0x30000>;
>  		#clock-cells = <1>;
> -	};
> +
> +		arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5
> 0 0 2 0>,
> +				      <1600000 1600000 0 3 7 7 7 1 4
> 0 0 2 0>,
> +				      <1500000 1500000 0 2 7 7 7 1 4
> 0 0 2 0>,
> +				      <1400000 1400000 0 2 7 7 6 1 4
> 0 0 2 0>,
> +				      <1300000 1300000 0 2 7 7 6 1 3
> 0 0 2 0>,
> +				      <1200000 1200000 0 2 7 7 5 1 3
> 0 0 2 0>,
> +				      <1100000 1100000 0 3 7 7 5 1 3
> 0 0 2 0>,
> +				      <1000000 1000000 0 1 7 7 4 1 2
> 0 0 2 0>,
> +				      < 900000  900000 0 1 7 7 4 1 2
> 0 0 2 0>,
> +				      < 800000  800000 0 1 7 7 4 1 2
> 0 0 2 0>,
> +				      < 700000  700000 0 1 7 7 3 1 1
> 0 0 2 0>,
> +				      < 600000  600000 0 1 7 7 3 1 1
> 0 0 2 0>,
> +				      < 500000  500000 0 1 7 7 2 1 1
> 0 0 2 0>,
> +				      < 400000  400000 0 1 7 7 2 1 1
> 0 0 2 0>,
> +				      < 300000  300000 0 1 7 7 1 1 1
> 0 0 2 0>,
> +				      < 200000  200000 0 1 7 7 1 1 1
> 0 0 2 0>;
> +	};
>  
>  	clock_audss: audss-clock-controller at 3810000 {
>  		compatible = "samsung,exynos5250-audss-clock";



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-01-18 12:10 ` [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock Thomas Abraham
@ 2014-01-20  7:47   ` Lukasz Majewski
  2014-01-21  7:52     ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-20  7:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> With the addition of the new Samsung specific cpu-clock type, the
> arm clock can be represented as a cpu-clock type and the independent
> clock blocks that made up the arm clock can be removed.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
>  drivers/clk/samsung/clk-exynos4.c                  |   11 +++++------
>  drivers/clk/samsung/clk-exynos5250.c               |    8 ++++----
>  include/dt-bindings/clock/exynos5250.h             |    1 +
>  4 files changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git
> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt index
> 99eae9c..acf867a 100644 ---
> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt +++
> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt @@
> -38,6 +38,7 @@ clock which they consume. ---------------------------- 
>    fin_pll		1
> +  armclk		12
>  
>    [Clock Gate for Special Clocks]
>  
> diff --git a/drivers/clk/samsung/clk-exynos4.c
> b/drivers/clk/samsung/clk-exynos4.c index 010f071..efcf4a3 100644
> --- a/drivers/clk/samsung/clk-exynos4.c
> +++ b/drivers/clk/samsung/clk-exynos4.c
> @@ -437,8 +437,6 @@ static struct samsung_mux_clock
> exynos4x12_mux_clks[] __initdata = { 
>  /* list of divider clocks supported in all exynos4 soc's */
>  static struct samsung_div_clock exynos4_div_clks[] __initdata = {
> -	DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3),
> -	DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3),
>  	DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
>  	DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
>  	DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
> @@ -484,8 +482,8 @@ static struct samsung_div_clock
> exynos4_div_clks[] __initdata = { DIV(0, "div_spi_pre2", "div_spi2",
> DIV_PERIL2, 8, 8), DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0,
> 4), DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
> -	DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
> -	DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
> 3),
> +	DIV_F(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
> 3,
> +			CLK_GET_RATE_NOCACHE, 0),
>  	DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
>  			CLK_SET_RATE_PARENT, 0),
>  	DIV_F(0, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
> @@ -870,7 +868,6 @@ static struct samsung_gate_clock
> exynos4x12_gate_clks[] __initdata = { 
>  static struct samsung_clock_alias exynos4_aliases[] __initdata = {
>  	ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
> -	ALIAS(CLK_ARM_CLK, NULL, "armclk"),
>  	ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"),
>  };
>  
> @@ -1125,12 +1122,14 @@ static void __init exynos4_clk_init(struct
> device_node *np, samsung_clk_register_alias(exynos4_aliases,
>  			ARRAY_SIZE(exynos4_aliases));
>  
> +	samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
> reg_base); +

I've got some doubts about allowing only the "mout_apll" clock to be the
only parent for armclk Samsung clock.

For the Exynos4412 it is also valid to have SCLK_MPLL_USER_C [*] as a
parent for this clock.

The problem is that you are reparenting the armclk to [*] with the
register modification - no CCF involved.

I just would like to know if this is yours design decision or
something, that we have overlooked in the v1 of this patch series.

>  	pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
>  		"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk =
> %ld\n", exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
>  		_get_rate("sclk_apll"),
> _get_rate("sclk_mpll"), _get_rate("sclk_epll"),
> _get_rate("sclk_vpll"),
> -		_get_rate("arm_clk"));
> +		_get_rate("armclk"));
>  }
>  
>  
> diff --git a/drivers/clk/samsung/clk-exynos5250.c
> b/drivers/clk/samsung/clk-exynos5250.c index ff4beeb..487be36 100644
> --- a/drivers/clk/samsung/clk-exynos5250.c
> +++ b/drivers/clk/samsung/clk-exynos5250.c
> @@ -298,9 +298,8 @@ static struct samsung_div_clock
> exynos5250_div_clks[] __initdata = { /*
>  	 * CMU_CPU
>  	 */
> -	DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
> -	DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
> -	DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3, "armclk"),
> +	DIV_F(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
> +			CLK_GET_RATE_NOCACHE, 0),
>  
>  	/*
>  	 * CMU_TOP
> @@ -684,8 +683,9 @@ static void __init exynos5250_clk_init(struct
> device_node *np) ARRAY_SIZE(exynos5250_div_clks));
>  	samsung_clk_register_gate(exynos5250_gate_clks,
>  			ARRAY_SIZE(exynos5250_gate_clks));
> +	samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
> reg_base); 
>  	pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
> -			_get_rate("div_arm2"));
> +			_get_rate("armclk"));
>  }
>  CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock",
> exynos5250_clk_init); diff --git
> a/include/dt-bindings/clock/exynos5250.h
> b/include/dt-bindings/clock/exynos5250.h index 922f2dc..59a10fb
> 100644 --- a/include/dt-bindings/clock/exynos5250.h +++
> b/include/dt-bindings/clock/exynos5250.h @@ -21,6 +21,7 @@
>  #define CLK_FOUT_CPLL		6
>  #define CLK_FOUT_EPLL		7
>  #define CLK_FOUT_VPLL		8
> +#define CLK_ARM_CLK		12
>  
>  /* gate for special clocks (sclk) */
>  #define CLK_SCLK_CAM_BAYER	128



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver
  2014-01-18 12:10 ` [PATCH v2 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver Thomas Abraham
@ 2014-01-20  7:48   ` Lukasz Majewski
  0 siblings, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-20  7:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> Remove the platform device instantiation for Exynos specific cpufreq
> driver and add the platform device for cpufreq-cpu0 driver.
> 
> Cc: Kukjin Kim <kgene.kim@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  arch/arm/mach-exynos/common.c          |    5 -----
>  arch/arm/mach-exynos/common.h          |    1 -
>  arch/arm/mach-exynos/mach-exynos4-dt.c |    2 +-
>  arch/arm/mach-exynos/mach-exynos5-dt.c |    2 +-
>  4 files changed, 2 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm/mach-exynos/common.c
> b/arch/arm/mach-exynos/common.c index f18be40..72ae5d3 100644
> --- a/arch/arm/mach-exynos/common.c
> +++ b/arch/arm/mach-exynos/common.c
> @@ -303,11 +303,6 @@ void __init exynos_cpuidle_init(void)
>  	platform_device_register(&exynos_cpuidle);
>  }
>  
> -void __init exynos_cpufreq_init(void)
> -{
> -	platform_device_register_simple("exynos-cpufreq", -1, NULL,
> 0); -}
> -
>  void __init exynos_init_late(void)
>  {
>  	if (of_machine_is_compatible("samsung,exynos5440"))
> diff --git a/arch/arm/mach-exynos/common.h
> b/arch/arm/mach-exynos/common.h index f76967b..0c31b34 100644
> --- a/arch/arm/mach-exynos/common.h
> +++ b/arch/arm/mach-exynos/common.h
> @@ -22,7 +22,6 @@ void exynos_init_io(void);
>  void exynos4_restart(enum reboot_mode mode, const char *cmd);
>  void exynos5_restart(enum reboot_mode mode, const char *cmd);
>  void exynos_cpuidle_init(void);
> -void exynos_cpufreq_init(void);
>  void exynos_init_late(void);
>  
>  void exynos_firmware_init(void);
> diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c
> b/arch/arm/mach-exynos/mach-exynos4-dt.c index d3e54b7..9a25320 100644
> --- a/arch/arm/mach-exynos/mach-exynos4-dt.c
> +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c
> @@ -22,8 +22,8 @@
>  static void __init exynos4_dt_machine_init(void)
>  {
>  	exynos_cpuidle_init();
> -	exynos_cpufreq_init();
>  
> +	platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0);
>  	of_platform_populate(NULL, of_default_bus_match_table, NULL,
> NULL); }
>  
> diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c
> b/arch/arm/mach-exynos/mach-exynos5-dt.c index 37ea261..9dc3710 100644
> --- a/arch/arm/mach-exynos/mach-exynos5-dt.c
> +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c
> @@ -44,8 +44,8 @@ static void __init exynos5_dt_machine_init(void)
>  	}
>  
>  	exynos_cpuidle_init();
> -	exynos_cpufreq_init();
>  
> +	platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0);
>  	of_platform_populate(NULL, of_default_bus_match_table, NULL,
> NULL); }
>  

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-01-18 12:10 ` [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support Thomas Abraham
@ 2014-01-20  8:08   ` Lukasz Majewski
  2014-01-21  8:08     ` Thomas Abraham
  2014-02-05 10:21     ` Thomas Abraham
  0 siblings, 2 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-20  8:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched
> over to use cpufreq-cpu0 driver for cpufreq functionality. So the
> Exynos specific cpufreq drivers for these platforms can be removed.
> 
> Cc: Kukjin Kim <kgene.kim@samsung.com>
> Cc: Jaecheol Lee <jc.lee@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  drivers/cpufreq/Kconfig.arm          |   36 ----
>  drivers/cpufreq/Makefile             |    4 -
>  drivers/cpufreq/exynos-cpufreq.c     |  292
> ----------------------------------
> drivers/cpufreq/exynos-cpufreq.h     |   91 -----------
> drivers/cpufreq/exynos4210-cpufreq.c |  157 ------------------
> drivers/cpufreq/exynos4x12-cpufreq.c |  211 ------------------------
> drivers/cpufreq/exynos5250-cpufreq.c |  183 --------------------- 7
> files changed, 0 insertions(+), 974 deletions(-) delete mode 100644
> drivers/cpufreq/exynos-cpufreq.c delete mode 100644
> drivers/cpufreq/exynos-cpufreq.h delete mode 100644
> drivers/cpufreq/exynos4210-cpufreq.c delete mode 100644
> drivers/cpufreq/exynos4x12-cpufreq.c delete mode 100644
> drivers/cpufreq/exynos5250-cpufreq.c
> 
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 3129749..704656d 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -16,42 +16,6 @@ config ARM_DT_BL_CPUFREQ
>  	  This enables probing via DT for Generic CPUfreq driver for
> ARM big.LITTLE platform. This gets frequency tables from DT.
>  
> -config ARM_EXYNOS_CPUFREQ
> -	bool
> -
> -config ARM_EXYNOS4210_CPUFREQ
> -	bool "SAMSUNG EXYNOS4210"
> -	depends on CPU_EXYNOS4210
> -	default y
> -	select ARM_EXYNOS_CPUFREQ
> -	help
> -	  This adds the CPUFreq driver for Samsung EXYNOS4210
> -	  SoC (S5PV310 or S5PC210).
> -
> -	  If in doubt, say N.
> -
> -config ARM_EXYNOS4X12_CPUFREQ
> -	bool "SAMSUNG EXYNOS4x12"
> -	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
> -	default y
> -	select ARM_EXYNOS_CPUFREQ
> -	help
> -	  This adds the CPUFreq driver for Samsung EXYNOS4X12
> -	  SoC (EXYNOS4212 or EXYNOS4412).
> -
> -	  If in doubt, say N.
> -
> -config ARM_EXYNOS5250_CPUFREQ
> -	bool "SAMSUNG EXYNOS5250"
> -	depends on SOC_EXYNOS5250
> -	default y
> -	select ARM_EXYNOS_CPUFREQ
> -	help
> -	  This adds the CPUFreq driver for Samsung EXYNOS5250
> -	  SoC.
> -
> -	  If in doubt, say N.
> -
>  config ARM_EXYNOS5440_CPUFREQ
>  	bool "SAMSUNG EXYNOS5440"
>  	depends on SOC_EXYNOS5440
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 7494565..3abfe05 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -49,10 +49,6 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ)		+=
> arm_big_little_dt.o 
>  obj-$(CONFIG_ARCH_DAVINCI_DA850)	+= davinci-cpufreq.o
>  obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
> -obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)	+= exynos-cpufreq.o
> -obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
> -obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
> -obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
>  obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ)	+= exynos5440-cpufreq.o
>  obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
>  obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)		+= imx6q-cpufreq.o
> diff --git a/drivers/cpufreq/exynos-cpufreq.c
> b/drivers/cpufreq/exynos-cpufreq.c deleted file mode 100644
> index fcd2914..0000000
> --- a/drivers/cpufreq/exynos-cpufreq.c
> +++ /dev/null
> @@ -1,292 +0,0 @@
> -/*
> - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
> - *		http://www.samsung.com
> - *
> - * EXYNOS - CPU frequency scaling support for EXYNOS series
> - *
> - * 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.
> -*/
> -
> -#include <linux/kernel.h>
> -#include <linux/err.h>
> -#include <linux/clk.h>
> -#include <linux/io.h>
> -#include <linux/slab.h>
> -#include <linux/regulator/consumer.h>
> -#include <linux/cpufreq.h>
> -#include <linux/suspend.h>
> -#include <linux/platform_device.h>
> -
> -#include <plat/cpu.h>
> -
> -#include "exynos-cpufreq.h"
> -
> -static struct exynos_dvfs_info *exynos_info;
> -
> -static struct regulator *arm_regulator;
> -
> -static unsigned int locking_frequency;
> -static bool frequency_locked;
> -static DEFINE_MUTEX(cpufreq_lock);
> -
> -static int exynos_cpufreq_get_index(unsigned int freq)
> -{
> -	struct cpufreq_frequency_table *freq_table =
> exynos_info->freq_table;
> -	int index;
> -
> -	for (index = 0;
> -		freq_table[index].frequency != CPUFREQ_TABLE_END;
> index++)
> -		if (freq_table[index].frequency == freq)
> -			break;
> -
> -	if (freq_table[index].frequency == CPUFREQ_TABLE_END)
> -		return -EINVAL;
> -
> -	return index;
> -}
> -
> -static int exynos_cpufreq_scale(unsigned int target_freq)
> -{
> -	struct cpufreq_frequency_table *freq_table =
> exynos_info->freq_table;
> -	unsigned int *volt_table = exynos_info->volt_table;
> -	struct cpufreq_policy *policy = cpufreq_cpu_get(0);
> -	unsigned int arm_volt, safe_arm_volt = 0;
> -	unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
> -	unsigned int old_freq;
> -	int index, old_index;
> -	int ret = 0;
> -
> -	old_freq = policy->cur;
> -
> -	/*
> -	 * The policy max have been changed so that we cannot get
> proper
> -	 * old_index with cpufreq_frequency_table_target(). Thus,
> ignore
> -	 * policy and get the index from the raw frequency table.
> -	 */
> -	old_index = exynos_cpufreq_get_index(old_freq);
> -	if (old_index < 0) {
> -		ret = old_index;
> -		goto out;
> -	}
> -
> -	index = exynos_cpufreq_get_index(target_freq);
> -	if (index < 0) {
> -		ret = index;
> -		goto out;
> -	}
> -
> -	/*
> -	 * ARM clock source will be changed APLL to MPLL temporary
> -	 * To support this level, need to control regulator for
> -	 * required voltage level
> -	 */
> -	if (exynos_info->need_apll_change != NULL) {
> -		if (exynos_info->need_apll_change(old_index, index)
> &&
> -		   (freq_table[index].frequency < mpll_freq_khz) &&
> -		   (freq_table[old_index].frequency < mpll_freq_khz))
> -			safe_arm_volt =
> volt_table[exynos_info->pll_safe_idx];
> -	}
> -	arm_volt = volt_table[index];
> -
> -	/* When the new frequency is higher than current frequency */
> -	if ((target_freq > old_freq) && !safe_arm_volt) {
> -		/* Firstly, voltage up to increase frequency */
> -		ret = regulator_set_voltage(arm_regulator, arm_volt,
> arm_volt);
> -		if (ret) {
> -			pr_err("%s: failed to set cpu voltage to
> %d\n",
> -				__func__, arm_volt);
> -			return ret;
> -		}
> -	}
> -
> -	if (safe_arm_volt) {
> -		ret = regulator_set_voltage(arm_regulator,
> safe_arm_volt,
> -				      safe_arm_volt);
> -		if (ret) {
> -			pr_err("%s: failed to set cpu voltage to
> %d\n",
> -				__func__, safe_arm_volt);
> -			return ret;
> -		}
> -	}
> -
> -	exynos_info->set_freq(old_index, index);
> -
> -	/* When the new frequency is lower than current frequency */
> -	if ((target_freq < old_freq) ||
> -	   ((target_freq > old_freq) && safe_arm_volt)) {
> -		/* down the voltage after frequency change */
> -		ret = regulator_set_voltage(arm_regulator, arm_volt,
> -				arm_volt);
> -		if (ret) {
> -			pr_err("%s: failed to set cpu voltage to
> %d\n",
> -				__func__, arm_volt);
> -			goto out;
> -		}
> -	}
> -
> -out:
> -	cpufreq_cpu_put(policy);
> -
> -	return ret;
> -}
> -
> -static int exynos_target(struct cpufreq_policy *policy, unsigned int
> index) -{
> -	struct cpufreq_frequency_table *freq_table =
> exynos_info->freq_table;
> -	int ret = 0;
> -
> -	mutex_lock(&cpufreq_lock);
> -
> -	if (frequency_locked)
> -		goto out;
> -
> -	ret = exynos_cpufreq_scale(freq_table[index].frequency);
> -
> -out:
> -	mutex_unlock(&cpufreq_lock);
> -
> -	return ret;
> -}
> -
> -#ifdef CONFIG_PM
> -static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
> -{
> -	return 0;
> -}
> -
> -static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
> -{
> -	return 0;
> -}
> -#endif
> -
> -/**
> - * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in
> suspend-resume
> - *			context
> - * @notifier
> - * @pm_event
> - * @v
> - *
> - * While frequency_locked == true, target() ignores every frequency
> but
> - * locking_frequency. The locking_frequency value is the initial
> frequency,
> - * which is set by the bootloader. In order to eliminate possible
> - * inconsistency in clock values, we save and restore frequencies
> during
> - * suspend and resume and block CPUFREQ activities. Note that the
> standard
> - * suspend/resume cannot be used as they are too deep (syscore_ops)
> for
> - * regulator actions.
> - */
> -static int exynos_cpufreq_pm_notifier(struct notifier_block
> *notifier,
> -				       unsigned long pm_event, void
> *v) -{
> -	int ret;
> -
> -	switch (pm_event) {
> -	case PM_SUSPEND_PREPARE:
> -		mutex_lock(&cpufreq_lock);
> -		frequency_locked = true;
> -		mutex_unlock(&cpufreq_lock);
> -
> -		ret = exynos_cpufreq_scale(locking_frequency);
> -		if (ret < 0)
> -			return NOTIFY_BAD;
> -
> -		break;
> -
> -	case PM_POST_SUSPEND:
> -		mutex_lock(&cpufreq_lock);
> -		frequency_locked = false;
> -		mutex_unlock(&cpufreq_lock);
> -		break;
> -	}
> -
> -	return NOTIFY_OK;
> -}
> -
> -static struct notifier_block exynos_cpufreq_nb = {
> -	.notifier_call = exynos_cpufreq_pm_notifier,
> -};
> -
> -static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
> -{
> -	policy->clk = exynos_info->cpu_clk;
> -	return cpufreq_generic_init(policy, exynos_info->freq_table,
> 100000); -}
> -
> -static struct cpufreq_driver exynos_driver = {
> -	.flags		= CPUFREQ_STICKY |
> CPUFREQ_NEED_INITIAL_FREQ_CHECK,
> -	.verify		=
> cpufreq_generic_frequency_table_verify,
> -	.target_index	= exynos_target,
> -	.get		= cpufreq_generic_get,
> -	.init		= exynos_cpufreq_cpu_init,
> -	.exit		= cpufreq_generic_exit,
> -	.name		= "exynos_cpufreq",
> -	.attr		= cpufreq_generic_attr,
> -#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
> -	.boost_supported = true,
> -#endif
> -#ifdef CONFIG_PM
> -	.suspend	= exynos_cpufreq_suspend,
> -	.resume		= exynos_cpufreq_resume,
> -#endif
> -};
> -
> -static int exynos_cpufreq_probe(struct platform_device *pdev)
> -{
> -	int ret = -EINVAL;
> -
> -	exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
> -	if (!exynos_info)
> -		return -ENOMEM;
> -
> -	if (soc_is_exynos4210())
> -		ret = exynos4210_cpufreq_init(exynos_info);
> -	else if (soc_is_exynos4212() || soc_is_exynos4412())
> -		ret = exynos4x12_cpufreq_init(exynos_info);
> -	else if (soc_is_exynos5250())
> -		ret = exynos5250_cpufreq_init(exynos_info);
> -	else
> -		return 0;
> -
> -	if (ret)
> -		goto err_vdd_arm;
> -
> -	if (exynos_info->set_freq == NULL) {
> -		pr_err("%s: No set_freq function (ERR)\n", __func__);
> -		goto err_vdd_arm;
> -	}
> -
> -	arm_regulator = regulator_get(NULL, "vdd_arm");
> -	if (IS_ERR(arm_regulator)) {
> -		pr_err("%s: failed to get resource vdd_arm\n",
> __func__);
> -		goto err_vdd_arm;
> -	}
> -
> -	locking_frequency = clk_get_rate(exynos_info->cpu_clk) /
> 1000; -
> -	register_pm_notifier(&exynos_cpufreq_nb);
> -
> -	if (cpufreq_register_driver(&exynos_driver)) {
> -		pr_err("%s: failed to register cpufreq driver\n",
> __func__);
> -		goto err_cpufreq;
> -	}
> -
> -	return 0;
> -err_cpufreq:
> -	unregister_pm_notifier(&exynos_cpufreq_nb);
> -
> -	regulator_put(arm_regulator);
> -err_vdd_arm:
> -	kfree(exynos_info);
> -	return -EINVAL;
> -}
> -
> -static struct platform_driver exynos_cpufreq_platdrv = {
> -	.driver = {
> -		.name	= "exynos-cpufreq",
> -		.owner	= THIS_MODULE,
> -	},
> -	.probe = exynos_cpufreq_probe,
> -};
> -module_platform_driver(exynos_cpufreq_platdrv);
> diff --git a/drivers/cpufreq/exynos-cpufreq.h
> b/drivers/cpufreq/exynos-cpufreq.h deleted file mode 100644
> index 3ddade8..0000000
> --- a/drivers/cpufreq/exynos-cpufreq.h
> +++ /dev/null
> @@ -1,91 +0,0 @@
> -/*
> - * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> - *		http://www.samsung.com
> - *
> - * EXYNOS - CPUFreq 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.
> -*/
> -
> -enum cpufreq_level_index {
> -	L0, L1, L2, L3, L4,
> -	L5, L6, L7, L8, L9,
> -	L10, L11, L12, L13, L14,
> -	L15, L16, L17, L18, L19,
> -	L20,
> -};
> -
> -#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m,
> p, s) \
> -	{ \
> -		.freq = (f) * 1000, \
> -		.clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3)
> << 12 | \
> -			(a4) << 16 | (a5) << 20 | (a6) << 24 | (a7)
> << 28), \
> -		.clk_div_cpu1 = (b0 << 0 | b1 << 4 | b2 << 8), \
> -		.mps = ((m) << 16 | (p) << 8 | (s)), \
> -	}
> -
> -struct apll_freq {
> -	unsigned int freq;
> -	u32 clk_div_cpu0;
> -	u32 clk_div_cpu1;
> -	u32 mps;
> -};
> -
> -struct exynos_dvfs_info {
> -	unsigned long	mpll_freq_khz;
> -	unsigned int	pll_safe_idx;
> -	struct clk	*cpu_clk;
> -	unsigned int	*volt_table;
> -	struct cpufreq_frequency_table	*freq_table;
> -	void (*set_freq)(unsigned int, unsigned int);
> -	bool (*need_apll_change)(unsigned int, unsigned int);
> -};
> -
> -#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
> -extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
> -#else
> -static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info
> *info) -{
> -	return -EOPNOTSUPP;
> -}
> -#endif
> -#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
> -extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
> -#else
> -static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info
> *info) -{
> -	return -EOPNOTSUPP;
> -}
> -#endif
> -#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
> -extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
> -#else
> -static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info
> *info) -{
> -	return -EOPNOTSUPP;
> -}
> -#endif
> -
> -#include <plat/cpu.h>
> -#include <mach/map.h>
> -
> -#define EXYNOS4_CLKSRC_CPU			(S5P_VA_CMU +
> 0x14200) -#define EXYNOS4_CLKMUX_STATCPU
> (S5P_VA_CMU + 0x14400) -
> -#define EXYNOS4_CLKDIV_CPU			(S5P_VA_CMU +
> 0x14500) -#define EXYNOS4_CLKDIV_CPU1
> (S5P_VA_CMU + 0x14504) -#define
> EXYNOS4_CLKDIV_STATCPU			(S5P_VA_CMU + 0x14600)
> -#define EXYNOS4_CLKDIV_STATCPU1			(S5P_VA_CMU +
> 0x14604) - -#define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT	(16)
> -#define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK	(0x7 <<
> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT) -
> -#define EXYNOS5_APLL_LOCK			(S5P_VA_CMU +
> 0x00000) -#define EXYNOS5_APLL_CON0
> (S5P_VA_CMU + 0x00100) -#define
> EXYNOS5_CLKMUX_STATCPU			(S5P_VA_CMU + 0x00400)
> -#define EXYNOS5_CLKDIV_CPU0			(S5P_VA_CMU +
> 0x00500) -#define EXYNOS5_CLKDIV_CPU1
> (S5P_VA_CMU + 0x00504) -#define
> EXYNOS5_CLKDIV_STATCPU0			(S5P_VA_CMU + 0x00600)
> -#define EXYNOS5_CLKDIV_STATCPU1			(S5P_VA_CMU +
> 0x00604) diff --git a/drivers/cpufreq/exynos4210-cpufreq.c
> b/drivers/cpufreq/exynos4210-cpufreq.c deleted file mode 100644 index
> 40d84c4..0000000 --- a/drivers/cpufreq/exynos4210-cpufreq.c
> +++ /dev/null @@ -1,157 +0,0 @@
> -/*
> - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
> - *		http://www.samsung.com
> - *
> - * EXYNOS4210 - CPU frequency scaling 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.
> -*/
> -
> -#include <linux/module.h>
> -#include <linux/kernel.h>
> -#include <linux/err.h>
> -#include <linux/clk.h>
> -#include <linux/io.h>
> -#include <linux/slab.h>
> -#include <linux/cpufreq.h>
> -
> -#include "exynos-cpufreq.h"
> -
> -static struct clk *cpu_clk;
> -static struct clk *moutcore;
> -static struct clk *mout_mpll;
> -static struct clk *mout_apll;
> -
> -static unsigned int exynos4210_volt_table[] = {
> -	1250000, 1150000, 1050000, 975000, 950000,
> -};
> -
> -static struct cpufreq_frequency_table exynos4210_freq_table[] = {
> -	{L0, 1200 * 1000},
> -	{L1, 1000 * 1000},
> -	{L2,  800 * 1000},
> -	{L3,  500 * 1000},
> -	{L4,  200 * 1000},
> -	{0, CPUFREQ_TABLE_END},
> -};
> -
> -static struct apll_freq apll_freq_4210[] = {
> -	/*
> -	 * values:
> -	 * freq
> -	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> PCLK_DBG, APLL, RESERVED
> -	 * clock divider for COPY, HPM, RESERVED
> -	 * PLL M, P, S
> -	 */
> -	APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
> -	APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
> -	APLL_FREQ(800,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
> -	APLL_FREQ(500,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
> -	APLL_FREQ(200,  0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
> -};
> -
> -static void exynos4210_set_clkdiv(unsigned int div_index)
> -{
> -	unsigned int tmp;
> -
> -	/* Change Divider - CPU0 */
> -
> -	tmp = apll_freq_4210[div_index].clk_div_cpu0;
> -
> -	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
> -
> -	do {
> -		tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
> -	} while (tmp & 0x1111111);
> -
> -	/* Change Divider - CPU1 */
> -
> -	tmp = apll_freq_4210[div_index].clk_div_cpu1;
> -
> -	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
> -
> -	do {
> -		tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
> -	} while (tmp & 0x11);
> -}
> -
> -static void exynos4210_set_apll(unsigned int index)
> -{
> -	unsigned int tmp, freq = apll_freq_4210[index].freq;
> -
> -	/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> -	clk_set_parent(moutcore, mout_mpll);
> -
> -	do {
> -		tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
> -			>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
> -		tmp &= 0x7;
> -	} while (tmp != 0x2);
> -
> -	clk_set_rate(mout_apll, freq * 1000);
> -
> -	/* MUX_CORE_SEL = APLL */
> -	clk_set_parent(moutcore, mout_apll);
> -
> -	do {
> -		tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
> -		tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
> -	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
> -}
> -
> -static void exynos4210_set_frequency(unsigned int old_index,
> -				     unsigned int new_index)
> -{
> -	if (old_index > new_index) {
> -		exynos4210_set_clkdiv(new_index);
> -		exynos4210_set_apll(new_index);
> -	} else if (old_index < new_index) {
> -		exynos4210_set_apll(new_index);
> -		exynos4210_set_clkdiv(new_index);
> -	}
> -}
> -
> -int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
> -{
> -	unsigned long rate;
> -
> -	cpu_clk = clk_get(NULL, "armclk");
> -	if (IS_ERR(cpu_clk))
> -		return PTR_ERR(cpu_clk);
> -
> -	moutcore = clk_get(NULL, "moutcore");
> -	if (IS_ERR(moutcore))
> -		goto err_moutcore;
> -
> -	mout_mpll = clk_get(NULL, "mout_mpll");
> -	if (IS_ERR(mout_mpll))
> -		goto err_mout_mpll;
> -
> -	rate = clk_get_rate(mout_mpll) / 1000;
> -
> -	mout_apll = clk_get(NULL, "mout_apll");
> -	if (IS_ERR(mout_apll))
> -		goto err_mout_apll;
> -
> -	info->mpll_freq_khz = rate;
> -	/* 800Mhz */
> -	info->pll_safe_idx = L2;
> -	info->cpu_clk = cpu_clk;
> -	info->volt_table = exynos4210_volt_table;
> -	info->freq_table = exynos4210_freq_table;
> -	info->set_freq = exynos4210_set_frequency;
> -
> -	return 0;
> -
> -err_mout_apll:
> -	clk_put(mout_mpll);
> -err_mout_mpll:
> -	clk_put(moutcore);
> -err_moutcore:
> -	clk_put(cpu_clk);
> -
> -	pr_debug("%s: failed initialization\n", __func__);
> -	return -EINVAL;
> -}
> diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c
> b/drivers/cpufreq/exynos4x12-cpufreq.c deleted file mode 100644
> index 7c11ace..0000000
> --- a/drivers/cpufreq/exynos4x12-cpufreq.c
> +++ /dev/null
> @@ -1,211 +0,0 @@
> -/*
> - * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
> - *		http://www.samsung.com
> - *
> - * EXYNOS4X12 - CPU frequency scaling 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.
> -*/
> -
> -#include <linux/module.h>
> -#include <linux/kernel.h>
> -#include <linux/err.h>
> -#include <linux/clk.h>
> -#include <linux/io.h>
> -#include <linux/slab.h>
> -#include <linux/cpufreq.h>
> -
> -#include "exynos-cpufreq.h"
> -
> -static struct clk *cpu_clk;
> -static struct clk *moutcore;
> -static struct clk *mout_mpll;
> -static struct clk *mout_apll;
> -
> -static unsigned int exynos4x12_volt_table[] = {
> -	1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
> 1037500,
> -	1000000,  987500,  975000,  950000,  925000,  900000,  900000
> -};
> -
> -static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
> -	{CPUFREQ_BOOST_FREQ, 1500 * 1000},

Here, you are removing BOOST support for Exynos4412, without any code,
which brings back this functionality in the new code.

I'd propose adding new property to cpus node and during
operating-points parsing mark the entry at the cpufreq_frequency_table
accordingly.

> -	{L1, 1400 * 1000},
> -	{L2, 1300 * 1000},
> -	{L3, 1200 * 1000},
> -	{L4, 1100 * 1000},
> -	{L5, 1000 * 1000},
> -	{L6,  900 * 1000},
> -	{L7,  800 * 1000},
> -	{L8,  700 * 1000},
> -	{L9,  600 * 1000},
> -	{L10, 500 * 1000},
> -	{L11, 400 * 1000},
> -	{L12, 300 * 1000},
> -	{L13, 200 * 1000},
> -	{0, CPUFREQ_TABLE_END},
> -};
> -
> -static struct apll_freq *apll_freq_4x12;
> -
> -static struct apll_freq apll_freq_4212[] = {
> -	/*
> -	 * values:
> -	 * freq
> -	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> PCLK_DBG, APLL, CORE2
> -	 * clock divider for COPY, HPM, RESERVED
> -	 * PLL M, P, S
> -	 */
> -	APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
> -	APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
> -	APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
> -	APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
> -	APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
> -	APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
> -	APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
> -	APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
> -	APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
> -	APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
> -	APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
> -	APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
> -	APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
> -	APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
> -};
> -
> -static struct apll_freq apll_freq_4412[] = {
> -	/*
> -	 * values:
> -	 * freq
> -	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> PCLK_DBG, APLL, CORE2
> -	 * clock divider for COPY, HPM, CORES
> -	 * PLL M, P, S
> -	 */
> -	APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
> -	APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
> -	APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
> -	APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
> -	APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
> -	APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
> -	APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
> -	APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
> -	APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
> -	APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
> -	APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
> -	APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
> -	APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
> -	APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
> -};
> -
> -static void exynos4x12_set_clkdiv(unsigned int div_index)
> -{
> -	unsigned int tmp;
> -	unsigned int stat_cpu1;
> -
> -	/* Change Divider - CPU0 */
> -
> -	tmp = apll_freq_4x12[div_index].clk_div_cpu0;
> -
> -	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
> -
> -	while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
> -		cpu_relax();
> -
> -	/* Change Divider - CPU1 */
> -	tmp = apll_freq_4x12[div_index].clk_div_cpu1;
> -
> -	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
> -	if (soc_is_exynos4212())
> -		stat_cpu1 = 0x11;
> -	else
> -		stat_cpu1 = 0x111;
> -
> -	while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
> -		cpu_relax();
> -}
> -
> -static void exynos4x12_set_apll(unsigned int index)
> -{
> -	unsigned int tmp, freq = apll_freq_4x12[index].freq;
> -
> -	/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> -	clk_set_parent(moutcore, mout_mpll);
> -
> -	do {
> -		cpu_relax();
> -		tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
> -			>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
> -		tmp &= 0x7;
> -	} while (tmp != 0x2);
> -
> -	clk_set_rate(mout_apll, freq * 1000);
> -
> -	/* MUX_CORE_SEL = APLL */
> -	clk_set_parent(moutcore, mout_apll);
> -
> -	do {
> -		cpu_relax();
> -		tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
> -		tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
> -	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
> -}
> -
> -static void exynos4x12_set_frequency(unsigned int old_index,
> -				  unsigned int new_index)
> -{
> -	if (old_index > new_index) {
> -		exynos4x12_set_clkdiv(new_index);
> -		exynos4x12_set_apll(new_index);
> -	} else if (old_index < new_index) {
> -		exynos4x12_set_apll(new_index);
> -		exynos4x12_set_clkdiv(new_index);
> -	}
> -}
> -
> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
> -{
> -	unsigned long rate;
> -
> -	cpu_clk = clk_get(NULL, "armclk");
> -	if (IS_ERR(cpu_clk))
> -		return PTR_ERR(cpu_clk);
> -
> -	moutcore = clk_get(NULL, "moutcore");
> -	if (IS_ERR(moutcore))
> -		goto err_moutcore;
> -
> -	mout_mpll = clk_get(NULL, "mout_mpll");
> -	if (IS_ERR(mout_mpll))
> -		goto err_mout_mpll;
> -
> -	rate = clk_get_rate(mout_mpll) / 1000;
> -
> -	mout_apll = clk_get(NULL, "mout_apll");
> -	if (IS_ERR(mout_apll))
> -		goto err_mout_apll;
> -
> -	if (soc_is_exynos4212())
> -		apll_freq_4x12 = apll_freq_4212;
> -	else
> -		apll_freq_4x12 = apll_freq_4412;
> -
> -	info->mpll_freq_khz = rate;
> -	/* 800Mhz */
> -	info->pll_safe_idx = L7;
> -	info->cpu_clk = cpu_clk;
> -	info->volt_table = exynos4x12_volt_table;
> -	info->freq_table = exynos4x12_freq_table;
> -	info->set_freq = exynos4x12_set_frequency;
> -
> -	return 0;
> -
> -err_mout_apll:
> -	clk_put(mout_mpll);
> -err_mout_mpll:
> -	clk_put(moutcore);
> -err_moutcore:
> -	clk_put(cpu_clk);
> -
> -	pr_debug("%s: failed initialization\n", __func__);
> -	return -EINVAL;
> -}
> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
> index 5f90b82..0000000
> --- a/drivers/cpufreq/exynos5250-cpufreq.c
> +++ /dev/null
> @@ -1,183 +0,0 @@
> -/*
> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
> - *		http://www.samsung.com
> - *
> - * EXYNOS5250 - CPU frequency scaling 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.
> -*/
> -
> -#include <linux/module.h>
> -#include <linux/kernel.h>
> -#include <linux/err.h>
> -#include <linux/clk.h>
> -#include <linux/io.h>
> -#include <linux/slab.h>
> -#include <linux/cpufreq.h>
> -
> -#include <mach/map.h>
> -
> -#include "exynos-cpufreq.h"
> -
> -static struct clk *cpu_clk;
> -static struct clk *moutcore;
> -static struct clk *mout_mpll;
> -static struct clk *mout_apll;
> -
> -static unsigned int exynos5250_volt_table[] = {
> -	1300000, 1250000, 1225000, 1200000, 1150000,
> -	1125000, 1100000, 1075000, 1050000, 1025000,
> -	1012500, 1000000,  975000,  950000,  937500,
> -	925000
> -};
> -
> -static struct cpufreq_frequency_table exynos5250_freq_table[] = {
> -	{L0, 1700 * 1000},
> -	{L1, 1600 * 1000},
> -	{L2, 1500 * 1000},
> -	{L3, 1400 * 1000},
> -	{L4, 1300 * 1000},
> -	{L5, 1200 * 1000},
> -	{L6, 1100 * 1000},
> -	{L7, 1000 * 1000},
> -	{L8,  900 * 1000},
> -	{L9,  800 * 1000},
> -	{L10, 700 * 1000},
> -	{L11, 600 * 1000},
> -	{L12, 500 * 1000},
> -	{L13, 400 * 1000},
> -	{L14, 300 * 1000},
> -	{L15, 200 * 1000},
> -	{0, CPUFREQ_TABLE_END},
> -};
> -
> -static struct apll_freq apll_freq_5250[] = {
> -	/*
> -	 * values:
> -	 * freq
> -	 * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG,
> APLL, ARM2
> -	 * clock divider for COPY, HPM, RESERVED
> -	 * PLL M, P, S
> -	 */
> -	APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
> -	APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
> -	APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
> -	APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
> -	APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
> -	APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
> -	APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
> -	APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
> -	APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
> -	APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
> -	APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
> -	APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
> -	APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
> -	APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
> -	APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
> -	APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
> -};
> -
> -static void set_clkdiv(unsigned int div_index)
> -{
> -	unsigned int tmp;
> -
> -	/* Change Divider - CPU0 */
> -
> -	tmp = apll_freq_5250[div_index].clk_div_cpu0;
> -
> -	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
> -
> -	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
> -		cpu_relax();
> -
> -	/* Change Divider - CPU1 */
> -	tmp = apll_freq_5250[div_index].clk_div_cpu1;
> -
> -	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
> -
> -	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
> -		cpu_relax();
> -}
> -
> -static void set_apll(unsigned int index)
> -{
> -	unsigned int tmp;
> -	unsigned int freq = apll_freq_5250[index].freq;
> -
> -	/* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> -	clk_set_parent(moutcore, mout_mpll);
> -
> -	do {
> -		cpu_relax();
> -		tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
> -		tmp &= 0x7;
> -	} while (tmp != 0x2);
> -
> -	clk_set_rate(mout_apll, freq * 1000);
> -
> -	/* MUX_CORE_SEL = APLL */
> -	clk_set_parent(moutcore, mout_apll);
> -
> -	do {
> -		cpu_relax();
> -		tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
> -		tmp &= (0x7 << 16);
> -	} while (tmp != (0x1 << 16));
> -}
> -
> -static void exynos5250_set_frequency(unsigned int old_index,
> -				  unsigned int new_index)
> -{
> -	if (old_index > new_index) {
> -		set_clkdiv(new_index);
> -		set_apll(new_index);
> -	} else if (old_index < new_index) {
> -		set_apll(new_index);
> -		set_clkdiv(new_index);
> -	}
> -}
> -
> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
> -{
> -	unsigned long rate;
> -
> -	cpu_clk = clk_get(NULL, "armclk");
> -	if (IS_ERR(cpu_clk))
> -		return PTR_ERR(cpu_clk);
> -
> -	moutcore = clk_get(NULL, "mout_cpu");
> -	if (IS_ERR(moutcore))
> -		goto err_moutcore;
> -
> -	mout_mpll = clk_get(NULL, "mout_mpll");
> -	if (IS_ERR(mout_mpll))
> -		goto err_mout_mpll;
> -
> -	rate = clk_get_rate(mout_mpll) / 1000;
> -
> -	mout_apll = clk_get(NULL, "mout_apll");
> -	if (IS_ERR(mout_apll))
> -		goto err_mout_apll;
> -
> -	info->mpll_freq_khz = rate;
> -	/* 800Mhz */
> -	info->pll_safe_idx = L9;
> -	info->cpu_clk = cpu_clk;
> -	info->volt_table = exynos5250_volt_table;
> -	info->freq_table = exynos5250_freq_table;
> -	info->set_freq = exynos5250_set_frequency;
> -
> -	return 0;
> -
> -err_mout_apll:
> -	clk_put(mout_mpll);
> -err_mout_mpll:
> -	clk_put(moutcore);
> -err_moutcore:
> -	clk_put(cpu_clk);
> -
> -	pr_err("%s: failed initialization\n", __func__);
> -	return -EINVAL;
> -}



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
@ 2014-01-20  8:09   ` Lukasz Majewski
  2014-01-27  7:16   ` Shawn Guo
  2014-01-27 20:25   ` Mike Turquette
  2 siblings, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-20  8:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> On some platforms such as the Samsung Exynos, changing the frequency
> of the CPU clock requires changing the frequency of the PLL that is
> supplying the CPU clock. To change the frequency of the PLL, the CPU
> clock is temporarily reparented to another parent clock.
> 
> The clock frequency of this temporary parent clock could be much
> higher than the clock frequency of the PLL at the time of
> reparenting. Due to the temporary increase in the CPU clock speed,
> the CPU (and any other components in the CPU clock domain such as
> dividers, mux, etc.) have to to be operated at a higher voltage
> level, called the safe voltage level. This patch adds optional
> support to temporarily switch to a safe voltage level during CPU
> frequency transitions.
> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>  drivers/cpufreq/cpufreq-cpu0.c                     |   37
> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-)
> 
> diff --git
> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
> f055515..37453ab 100644 ---
> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@ -19,6
> +19,12 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to
> Documentation/devicetree/bindings/thermal/thermal.txt. +- safe-opp:
> Certain platforms require that during a opp transition,
> +  a system should not go below a particular opp level. For such
> systems,
> +  this property specifies the minimum opp to be maintained during the
> +  opp transitions. The safe-opp value is a tuple with first element
> +  representing the safe frequency and the second element
> representing the
> +  safe voltage.
>  
>  Examples:
>  
> @@ -36,6 +42,7 @@ cpus {
>  			396000  950000
>  			198000  850000
>  		>;
> +		safe-opp = <396000 950000>
>  		clock-latency = <61036>; /* two CLK32 periods */
>  		#cooling-cells = <2>;
>  		cooling-min-level = <0>;
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -27,6 +27,8 @@
>  
>  static unsigned int transition_latency;
>  static unsigned int voltage_tolerance; /* in percentage */
> +static unsigned long safe_frequency;
> +static unsigned long safe_voltage;
>  
>  static struct device *cpu_dev;
>  static struct clk *cpu_clk;
> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy
> *policy, unsigned int index) volt_old =
> regulator_get_voltage(cpu_reg); }
>  
> -	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> +	pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>  		 old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>  		 new_freq / 1000, volt ? volt / 1000 : -1);
>  
>  	/* scaling up?  scale voltage before frequency */
> -	if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> +	if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> +				new_freq >= safe_frequency) {
>  		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>  		if (ret) {
>  			pr_err("failed to scale voltage up: %d\n",
> ret); return ret;
>  		}
> +	} else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
> +		/*
> +		 * the scaled up voltage level for the new_freq is
> lower
> +		 * than the safe voltage level. so set safe_voltage
> +		 * as the intermediate voltage level and revert it
> +		 * back after the frequency has been changed.
> +		 */
> +		ret = regulator_set_voltage_tol(cpu_reg,
> safe_voltage, tol);
> +		if (ret) {
> +			pr_err("failed to set safe voltage: %d\n",
> ret);
> +			return ret;
> +		}
>  	}
>  
>  	ret = clk_set_rate(cpu_clk, freq_exact);
> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy
> *policy, unsigned int index) }
>  
>  	/* scaling down?  scale voltage after frequency */
> -	if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> +	if (!IS_ERR(cpu_reg) &&
> +			(new_freq < old_freq || new_freq <
> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg, volt,
> tol); if (ret) {
>  			pr_err("failed to scale voltage down: %d\n",
> ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
> cpu0_cpufreq_driver = { 
>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>  {
> +	const struct property *prop;
> +	struct dev_pm_opp *opp;
>  	struct device_node *np;
>  	int ret;
>  
> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
> platform_device *pdev) goto out_put_node;
>  	}
>  
> +	prop = of_find_property(np, "safe-opp", NULL);
> +	if (prop) {
> +		if (prop->value && (prop->length / sizeof(u32)) ==
> 2) {
> +			const __be32 *val;
> +			val = prop->value;
> +			safe_frequency = be32_to_cpup(val++);
> +			safe_voltage = be32_to_cpup(val);
> +		} else {
> +			pr_err("invalid safe-opp level specified\n");
> +		}
> +	}
> +
>  	of_property_read_u32(np, "voltage-tolerance",
> &voltage_tolerance); 
>  	if (of_property_read_u32(np, "clock-latency",
> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
>  
>  	if (!IS_ERR(cpu_reg)) {
> -		struct dev_pm_opp *opp;
>  		unsigned long min_uV, max_uV;
>  		int i;
>  

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-01-18 12:10 ` [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks Thomas Abraham
@ 2014-01-20  8:24   ` Lukasz Majewski
  2014-01-21  8:35     ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-20  8:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> The CPU clock provider supplies the clock to the CPU clock domain. The
> composition and organization of the CPU clock provider could vary
> among Exynos SoCs. A CPU clock provider can be composed of clock mux,
> dividers and gates. This patch defines a new clock type for CPU clock
> provider and adds infrastructure to register the CPU clock providers
> for Samsung platforms.
> 
> In addition to this, the arm cpu clock provider for Exynos4210 and
> compatible SoCs is instantiated using the new cpu clock type. The
> clock frequency table and the clock configuration data for this clock
> is obtained from device tree. This implementation is reusable for
> Exynos4x12 and Exynos5250 SoCs as well.
> 
> Cc: Tomasz Figa <t.figa@samsung.com>
> Cc: Lukasz Majewski <l.majewski@majess.pl>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  drivers/clk/samsung/Makefile  |    2 +-
>  drivers/clk/samsung/clk-cpu.c |  345
> +++++++++++++++++++++++++++++++++++++++++
> drivers/clk/samsung/clk.h     |    3 + 3 files changed, 349
> insertions(+), 1 deletions(-) create mode 100644
> drivers/clk/samsung/clk-cpu.c
> 
> diff --git a/drivers/clk/samsung/Makefile
> b/drivers/clk/samsung/Makefile index 8eb4799..e2b453f 100644
> --- a/drivers/clk/samsung/Makefile
> +++ b/drivers/clk/samsung/Makefile
> @@ -2,7 +2,7 @@
>  # Samsung Clock specific Makefile
>  #
>  
> -obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o
> +obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o clk-cpu.o
>  obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o
>  obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o
>  obj-$(CONFIG_SOC_EXYNOS5420)	+= clk-exynos5420.o
> diff --git a/drivers/clk/samsung/clk-cpu.c
> b/drivers/clk/samsung/clk-cpu.c new file mode 100644
> index 0000000..92fba45
> --- /dev/null
> +++ b/drivers/clk/samsung/clk-cpu.c
> @@ -0,0 +1,345 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + * Author: Thomas Abraham <thomas.ab@samsung.com>
> + *
> + * 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 contains the utility functions to register the cpu
> clocks
> + * for samsung platforms.
> +*/
> +
> +#include <linux/errno.h>
> +#include "clk.h"
> +
> +#define SRC_CPU			0x0
> +#define STAT_CPU		0x200
> +#define DIV_CPU0		0x300
> +#define DIV_CPU1		0x304
> +#define DIV_STAT_CPU0		0x400
> +#define DIV_STAT_CPU1		0x404
> +
> +/**
> + * struct samsung_cpuclk_freq_table: table of frequency supported by
> + * a cpu clock and associated data if any.
> + * @freq: points to a table of supported frequencies (in KHz)
> + * @freq_count: number of entries in the frequency table
> + * @data: cpu clock specific data, if any
> + *
> + * This structure holds the frequency options supported by the cpu
> clock in
> + * which this structure is contained. The data pointer is an
> optional data
> + * that can provide any additional configuration options for the
> supported
> + * frequencies. This structure is intended to be reusable for all
> cpu clocks
> + * in Samsung SoC based platforms
> + */
> +struct samsung_cpuclk_freq_table {
> +	const unsigned long	*freq;       /* in KHz */
> +	unsigned long		freq_count;
> +	const void		*data;
> +};
> +
> +/**
> + * struct exynos4210_freq_data: format of auxillary data associated
> with
> + * each frequency supported by the cpu clock for exynos4210.
> + * @parent_freq: The frequency of the parent clock required to
> generate the
> + * supported cpu clock speed.
> + * @div0: value to be programmed in the div_cpu0 register.
> + * @div1: value to be programmed in the div_cpu1 register.
> + *
> + * This structure holds the auxillary configuration data for each
> supported
> + * cpu clock frequency on Exynos4210 and compatible SoCs.
> + */
> +struct exynos4210_freq_data {
> +	unsigned long	parent_freq;
> +	unsigned int	div0;
> +	unsigned int	div1;
> +};
> +
> +/**
> + * struct samsung_cpuclk: information about clock supplied to a CPU
> core.
> + * @hw: handle between ccf and cpu clock.
> + * @ctrl_base: base address of the clock controller.
> + * @offset: offset from the ctrl_base address where the cpu clock
> div/mux
> + *          registers can be accessed.
> + * @parent: clock handle representing the clock output of the parent
> clock.
> + * @freq_table: the frequency table supported by this cpu clock.
> + */
> +struct samsung_cpuclk {
> +	struct clk_hw		hw;
> +	void __iomem		*ctrl_base;
> +	unsigned long		offset;
> +	struct clk		*parent;
> +	const struct samsung_cpuclk_freq_table *freq_table;
> +};
> +
> +#define to_samsung_cpuclk(hw)	container_of(hw, struct
> samsung_cpuclk, hw) +
> +/**
> + * struct samsung_cpuclk_match_data: soc specific data for cpu
> clocks.
> + * @parser: pointer to a function that can parse SoC specific cpu
> clock
> + *	frequency and associated configuration data.
> + * @offset: optional offset from base of clock controller register
> base,
> + *	to be used when accessing clock controller registers
> related to the
> + * cpu clock.
> + * @offset: offset from the ctrl_base address where the cpu clock
> div/mux
> + *	registers can be accessed.
> + */
> +struct samsung_cpuclk_match_data {
> +	int (*parser)(struct device_node *,
> +			struct samsung_cpuclk_freq_table **);
> +	unsigned int offset;
> +};
> +
> +/* This is a helper function to perform clock rounding for cpu
> clocks. */ +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	struct samsung_cpuclk *cpuclk = to_samsung_cpuclk(hw);
> +	const struct samsung_cpuclk_freq_table *freq_tbl;
> +	int i;
> +
> +	freq_tbl = cpuclk->freq_table;
> +	drate /= 1000;
> +
> +	for (i = 0; i < freq_tbl->freq_count; i++) {
> +		if (drate >= freq_tbl->freq[i])
> +			return freq_tbl->freq[i] * 1000;
> +	}
> +	return freq_tbl->freq[i - 1] * 1000;
> +}
> +
> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) +
> 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >>
> 28) & 0xf) + 1) +
> +/*
> + * CPU clock speed for Exynos4210 and compatible SoCs is
> + * parent clock speed / core1_ratio / core2_ratio
> + */
> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
> +				unsigned long parent_rate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +
> +	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> +				EXYNOS4210_ARM_DIV2(base);
> +}
> +
> +/* set rate callback for cpuclk type on Exynos4210 and similar SoCs
> */ +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned
> long drate,
> +					unsigned long prate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
> +	const struct samsung_cpuclk_freq_table *freq_tbl;
> +	const struct exynos4210_freq_data *freq_data;
> +	unsigned long mux_reg, idx;
> +	void __iomem *base;
> +
> +	if (drate == prate)
> +		return 0;
> +
> +	freq_tbl = armclk->freq_table;
> +	freq_data = freq_tbl->data;
> +	base = armclk->ctrl_base + armclk->offset;
> +
> +	for (idx = 0; idx < freq_tbl->freq_count; idx++, freq_data++)
> +		if ((freq_tbl->freq[idx] * 1000) == drate)
> +			break;
> +
> +	if (drate < prate) {
> +		mux_reg = readl(base + SRC_CPU);
> +		writel(mux_reg | (1 << 16), base + SRC_CPU);
> +		while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +			;
> +
> +		clk_set_rate(armclk->parent, drate);
> +	}
> +
> +	writel(freq_data->div0, base + DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +	writel(freq_data->div1, base + DIV_CPU1);
> +	while (readl(base + DIV_STAT_CPU1) != 0)
> +		;
> +
> +	if (drate > prate) {
> +		mux_reg = readl(base + SRC_CPU);
> +		writel(mux_reg | (1 << 16), base + SRC_CPU);
> +		while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +			;
> +
> +		clk_set_rate(armclk->parent, freq_data->parent_freq
> * 1000);
> +	}
> +
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> +			;
> +	return 0;
> +}
> +
> +/* clock ops for armclk on Exynos4210 and compatible platforms. */
> +static const struct clk_ops exynos4210_armclk_clk_ops = {
> +	.recalc_rate = exynos4210_armclk_recalc_rate,
> +	.round_rate = samsung_cpuclk_round_rate,
> +	.set_rate = exynos4210_armclk_set_rate,
> +};
> +
> +/* helper function to register a cpu clock */
> +static void __init samsung_cpuclk_register(unsigned int lookup_id,
> +		const char *name, const char *parent, const struct
> clk_ops *ops,
> +		const struct samsung_cpuclk_freq_table *freq_tbl,
> +		void __iomem *reg_base,
> +		const struct samsung_cpuclk_match_data *data)
> +{
> +	struct samsung_cpuclk *cpuclk;
> +	struct clk_init_data init;
> +	struct clk *clk;
> +
> +	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> +	if (!cpuclk) {
> +		pr_err("%s: could not allocate memory for cpuclk
> %s\n",
> +					__func__, name);
> +		return;
> +	}
> +
> +	init.name = name;
> +	init.flags = CLK_GET_RATE_NOCACHE;
> +	init.parent_names = &parent;
> +	init.num_parents = 1;
> +	init.ops = ops;
> +
> +	cpuclk->hw.init = &init;
> +	cpuclk->ctrl_base = reg_base;
> +	cpuclk->offset = data->offset;
> +	cpuclk->freq_table = freq_tbl;
> +	cpuclk->parent = __clk_lookup(parent);
> +
> +	clk = clk_register(NULL, &cpuclk->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: could not register cpuclk %s\n",
> __func__,	name);
> +		kfree(cpuclk);
> +		return;
> +	}
> +	samsung_clk_add_lookup(clk, lookup_id);
> +}
> +
> +#define EXYNOS4210_DIV_CPU01(d0, d1, d2, d3, d4, d5, d6,
> d7)		\
> +		((d0 << 28) | (d1 << 24) | (d2 << 20) |	(d3
> << 16) |	\
> +		 (d4 << 12) | (d5 << 8) | (d6 << 4) | (d7 << 0))
> +#define EXYNOS4210_DIV_CPU11(d0, d1,
> d2)				\
> +		((d0 << 8) | (d1 << 4) | (d2 << 0))
> +#define EXYNOS4210_CFG_LEN 13
> +
> +/*
> + * parse cpu clock frequency table and auxillary configuration data
> from dt
> + * for exynos4210 and compatible SoC's.
> + */
> +static int exynos4210_armclk_cfg_parser(struct device_node *np,
> +		struct samsung_cpuclk_freq_table **tbl)
> +{
> +	struct samsung_cpuclk_freq_table *freq_tbl;
> +	struct exynos4210_freq_data *fdata, *t_fdata;
> +	unsigned long *freqs, cfg[EXYNOS4210_CFG_LEN];
> +	const struct property *prop;
> +	unsigned int tbl_sz, i, j;
> +	const __be32 *val;
> +	int ret;
> +
> +	prop = of_find_property(np, "arm-frequency-table", NULL);
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -EINVAL;
> +	if ((prop->length / sizeof(u32)) % EXYNOS4210_CFG_LEN)

Cannot we have the EXYNOS4210_CFG_LEN parsed from DT as well?

> +		return -EINVAL;
> +	tbl_sz = (prop->length / sizeof(u32)) / EXYNOS4210_CFG_LEN;
> +
> +	freq_tbl = kzalloc(sizeof(*freq_tbl), GFP_KERNEL);
> +	if (!freq_tbl)
> +		return -ENOMEM;
> +
> +	freqs = kzalloc(sizeof(u32) * tbl_sz, GFP_KERNEL);
> +	if (!freqs) {
> +		ret = -ENOMEM;
> +		goto free_freq_tbl;
> +	}
> +
> +	fdata = kzalloc(sizeof(*fdata) * tbl_sz, GFP_KERNEL);
> +	if (!fdata) {
> +		ret = -ENOMEM;
> +		goto free_freqs;
> +	}
> +	t_fdata = fdata;
> +
> +	val = prop->value;
> +	for (i = 0; i < tbl_sz; i++, fdata++) {
> +		for (j = 0; j < EXYNOS4210_CFG_LEN; j++)
> +			cfg[j] = be32_to_cpup(val++);
> +		freqs[i] = cfg[0];
> +		fdata->parent_freq = cfg[1];

Why do we need the separate parent_freq entry here?

In the patch 4/7 the freqs (cfg[0]) and parent_freq (cfg[1]) values are
the same for all supported devices (at "arm-frequency-table").

What is the rationale for having those values duplicated in the DT?


> +		fdata->div0 = EXYNOS4210_DIV_CPU01(cfg[9], cfg[8],
> cfg[7],
> +				cfg[6], cfg[5], cfg[4], cfg[3],
> cfg[2]);
> +		fdata->div1 = EXYNOS4210_DIV_CPU11(cfg[12], cfg[11],
> cfg[10]);
> +	}
> +
> +	freq_tbl->freq = freqs;
> +	freq_tbl->freq_count = tbl_sz;
> +	freq_tbl->data = t_fdata;
> +	*tbl = freq_tbl;
> +	return 0;
> +
> +free_freqs:
> +	kfree(freqs);
> +free_freq_tbl:
> +	kfree(freq_tbl);
> +	return ret;
> +}
> +
> +static struct samsung_cpuclk_match_data exynos4210_cpuclk_match_data
> = {
> +	.parser = exynos4210_armclk_cfg_parser,
> +	.offset = 0x14200,
> +};
> +
> +static struct samsung_cpuclk_match_data exynos5250_cpuclk_match_data
> = {
> +	.parser = exynos4210_armclk_cfg_parser,
> +	.offset = 0x200,
> +};
> +
> +static const struct of_device_id samsung_clock_ids[] = {
> +	{ .compatible = "samsung,exynos4210-clock",
> +			.data = &exynos4210_cpuclk_match_data, },
> +	{ .compatible = "samsung,exynos4412-clock",
> +			.data = &exynos4210_cpuclk_match_data, },
> +	{ .compatible = "samsung,exynos5250-clock",
> +			.data = &exynos5250_cpuclk_match_data, },
> +};
> +
> +int __init samsung_register_arm_clock(struct device_node *np,
> +		unsigned int lookup_id,	const char *parent,
> void __iomem *base) +{
> +	const struct of_device_id *match;
> +	struct samsung_cpuclk_freq_table *freq_table;
> +	const struct samsung_cpuclk_match_data *data;
> +	int ret;
> +
> +	match = of_match_node(samsung_clock_ids, np);
> +	if (!match) {
> +		pr_err("%s: could not determine soc type\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	data = match->data;
> +	ret = data->parser(np, &freq_table);
> +	if (ret) {
> +		pr_err("%s: error %d in parsing arm clock freq
> table",
> +						__func__, ret);
> +		return -EINVAL;
> +	}
> +
> +	samsung_cpuclk_register(lookup_id, "armclk", parent,
> +		&exynos4210_armclk_clk_ops, freq_table, base, data);
> +
> +	return 0;
> +}
> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
> index 31b4174..a759330 100644
> --- a/drivers/clk/samsung/clk.h
> +++ b/drivers/clk/samsung/clk.h
> @@ -340,4 +340,7 @@ extern void __init
> samsung_clk_register_pll(struct samsung_pll_clock *pll_list, 
>  extern unsigned long _get_rate(const char *clk_name);
>  
> +extern int __init samsung_register_arm_clock(struct device_node *np,
> +		unsigned int lookup_id, const char *parent, void
> __iomem *base); +
>  #endif /* __SAMSUNG_CLK_H */



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5
  2014-01-18 15:22   ` Rob Herring
@ 2014-01-21  7:31     ` Thomas Abraham
  2014-01-24 15:24       ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21  7:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,


On Sat, Jan 18, 2014 at 8:52 PM, Rob Herring <robherring2@gmail.com> wrote:
> On Sat, Jan 18, 2014 at 6:10 AM, Thomas Abraham <ta.omasab@gmail.com> wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> The clk ops of the new Samsung cpu clock provider type requires configuration
>> data that will be programmed in the multiple clock blocks encapsulated within
>> the cpu clock provider type. This configuration data is held in the clock
>> controller node. Update clock binding documentation about this configuration
>> data format for Samsung Exynos4 and Exynos5 platforms.
>>
>> Cc: Rob Herring <robh+dt@kernel.org>
>
> Please copy all maintainers.

Okay.

>
>> Cc: Tomasz Figa <t.figa@samsung.com>
>> Cc: <devicetree@vger.kernel.org>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  .../devicetree/bindings/clock/exynos4-clock.txt    |   30 ++++++++++++++++++++
>>  .../devicetree/bindings/clock/exynos5250-clock.txt |   21 ++++++++++++++
>>  2 files changed, 51 insertions(+), 0 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
>> index a2ac2d9..c28aabd 100644
>> --- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
>> +++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
>> @@ -15,6 +15,29 @@ Required Properties:
>>
>>  - #clock-cells: should be 1.
>>
>> +- arm-frequency-table: defines the list of arm clock speeds supported and
>
> Seems like a Samsung specific property and nothing to do with ARM, so
> it should be named accordingly.

Okay.

>
>> +  the associated configuration values required to setup the clock controller
>> +  for generating those speeds. The format of each entry included in the
>> +  arm-frequency-table should be as defined below (#cells per entry = 13)
>> +
>> +  - for Exynos4210 and Exynos4212 based platforms:
>> +      cell #1: arm clock frequency
>> +      cell #2: expected arm clock parent frequency
>> +      cell #3 ~ cell 12#: value of clock divider in the following order
>> +              core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
>> +              atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
>> +              copy_ratio, hpm_ratio.
>> +      cell #13: reserved (should be zero).
>> +
>> +  - for Exynos4412 based platforms:
>> +      cell #1: arm clock frequency
>> +      cell #2: expected arm clock parent frequency
>> +      cell #3 ~ cell #13: value of clock divider in the following order
>> +              core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
>> +              atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
>> +              copy_ratio, hpm_ratio, cores_ratio
>
> You don't need voltages? Are the h/w limitations really ratios or each
> clock has a max frequency that must be maintained? I would expect the
> latter and think it would be better to specify maximum frequencies of
> each clock. Then you can calculate the dividers to keep frequencies in
> range.

Voltage is not needed here since the cpu clock speed is managed by the
cpufreq driver which will take care of setting appropriate voltage.
Any other users apart from cpufreq will have to setup the voltage
appropriately.

About the ratios, yes the user manual lists the optimal clock
frequency for these clocks. As suggested, I will remove the ratio list
for these clocks.

>
> How will this scale to multi-cluster chips with different frequency ranges?

Usually, each cluster would have its own independent clock input. So
there will be two or more cpu clocks in multi-cluster chips. So the
clocks can be independently programmed as required by the cluster.

>
> Rob
>

Thanks Rob for your review.

Thomas.

>> +
>> +
>>  The following is the list of clocks generated by the controller. Each clock is
>>  assigned an identifier and client nodes use this identifier to specify the
>>  clock which they consume. Some of the clocks are available only on a particular
>> @@ -275,6 +298,13 @@ Example 1: An example of a clock controller node is listed below.
>>                 compatible = "samsung,exynos4210-clock";
>>                 reg = <0x10030000 0x20000>;
>>                 #clock-cells = <1>;
>> +
>> +               arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7 0 5 0>,
>> +                                     <1000000 1000000 0 3 7 3 4 1 7 0 4 0>,
>> +                                     < 800000  800000 0 3 7 3 3 1 7 0 3 0>,
>> +                                     < 500000  500000 0 3 7 3 3 1 7 0 3 0>,
>> +                                     < 400000  400000 0 3 7 3 3 1 7 0 3 0>,
>> +                                     < 200000  200000 0 1 3 1 1 1 0 0 3 0>;
>>         };
>>
>>  Example 2: UART controller node that consumes the clock generated by the clock
>> diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>> index 72ce617..99eae9c 100644
>> --- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>> +++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>> @@ -13,6 +13,20 @@ Required Properties:
>>
>>  - #clock-cells: should be 1.
>>
>> +- arm-frequency-table: defines the list of arm clock speeds supported and
>> +  the associated configuration values required to setup the clock controller
>> +  for generating those speeds. The format of each entry included in the
>> +  arm-frequency-table should be as defined below (#cells per entry = 13)
>> +
>> +      cell #1: arm clock frequency
>> +      cell #2: expected arm clock parent frequency
>> +      cell #3 ~ cell #12: value of clock divider in the following order
>> +              arm_ratio, cpud_ratio, acp_ratio, periph_ratio,
>> +              atb_ratio, pclk_dbg_ratio, apll_ratio, arm2_ratio,
>> +              copy_ratio, hpm_ratio
>> +      cell #13: reserved (should be zero)
>> +
>> +
>>  The following is the list of clocks generated by the controller. Each clock is
>>  assigned an identifier and client nodes use this identifier to specify the
>>  clock which they consume.
>> @@ -177,6 +191,13 @@ Example 1: An example of a clock controller node is listed below.
>>                 compatible = "samsung,exynos5250-clock";
>>                 reg = <0x10010000 0x30000>;
>>                 #clock-cells = <1>;
>> +
>> +               arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5 0 0 2>,
>> +                                     <1600000 1600000 0 3 7 7 7 1 4 0 0 2>,
>> +                                     <1500000 1500000 0 2 7 7 7 1 4 0 0 2>,
>> +                                     <1400000 1400000 0 2 7 7 6 1 4 0 0 2>,
>> +                                     <1300000 1300000 0 2 7 7 6 1 3 0 0 2>,
>> +                                     <1200000 1200000 0 2 7 7 5 1 3 0 0 2>;
>>         };
>>
>>  Example 2: UART controller node that consumes the clock generated by the clock
>> --
>> 1.6.6.rc2
>>

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

* [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table
  2014-01-20  7:32   ` Lukasz Majewski
@ 2014-01-21  7:33     ` Thomas Abraham
  0 siblings, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21  7:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Mon, Jan 20, 2014 at 1:02 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> For all Exynos based platforms, add CPU nodes, operating points and
>> cpu clock frequency table for migrating from Exynos specific cpufreq
>> driver to using generic cpufreq-cpu0 driver.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  arch/arm/boot/dts/exynos4210-origen.dts         |    6 +++
>>  arch/arm/boot/dts/exynos4210-trats.dts          |    6 +++
>>  arch/arm/boot/dts/exynos4210-universal_c210.dts |    6 +++
>>  arch/arm/boot/dts/exynos4210.dtsi               |   35
>> ++++++++++++++++++ arch/arm/boot/dts/exynos4212.dtsi
>> |   17 +++++++++ arch/arm/boot/dts/exynos4412-odroidx.dts        |
>> 6 +++ arch/arm/boot/dts/exynos4412-origen.dts         |    6 +++
>>  arch/arm/boot/dts/exynos4412-trats2.dts         |    6 +++
>>  arch/arm/boot/dts/exynos4412.dtsi               |   30
>> ++++++++++++++++ arch/arm/boot/dts/exynos4x12.dtsi               |
>> 35 ++++++++++++++++++ arch/arm/boot/dts/exynos5250-arndale.dts
>> |    6 +++ arch/arm/boot/dts/exynos5250-cros-common.dtsi   |    6 +++
>>  arch/arm/boot/dts/exynos5250-smdk5250.dts       |    6 +++
>>  arch/arm/boot/dts/exynos5250.dtsi               |   43
>> ++++++++++++++++++++++- 14 files changed, 213 insertions(+), 1
>> deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/exynos4210-origen.dts
>> b/arch/arm/boot/dts/exynos4210-origen.dts index 2aa13cb..dd17e93
>> 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts
>> +++ b/arch/arm/boot/dts/exynos4210-origen.dts
>> @@ -32,6 +32,12 @@
>>               bootargs ="root=/dev/ram0 rw ramdisk=8192
>> initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck1_reg>;
>> +             };
>> +     };
>> +
>>       regulators {
>>               compatible = "simple-bus";
>>               #address-cells = <1>;
>> diff --git a/arch/arm/boot/dts/exynos4210-trats.dts
>> b/arch/arm/boot/dts/exynos4210-trats.dts index 63cc571..25487d7 100644
>> --- a/arch/arm/boot/dts/exynos4210-trats.dts
>> +++ b/arch/arm/boot/dts/exynos4210-trats.dts
>> @@ -30,6 +30,12 @@
>>               bootargs = "console=ttySAC2,115200N8
>> root=/dev/mmcblk0p5 rootwait earlyprintk panic=5"; };
>>
>> +     cpus {
>> +             cpu: cpu at 0 {
>> +                     cpu0-supply = <&varm_breg>;
>> +             };
>> +     };
>> +
>>       regulators {
>>               compatible = "simple-bus";
>>
>> diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts
>> b/arch/arm/boot/dts/exynos4210-universal_c210.dts index
>> d2e3f5f..74d5a70 100644 ---
>> a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++
>> b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -28,6 +28,12 @@
>>               bootargs = "console=ttySAC2,115200N8
>> root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1"; };
>>
>> +     cpus {
>> +             cpu: cpu at 0 {
>> +                     cpu0-supply = <&vdd_arm_reg>;
>> +             };
>> +     };
>> +
>>       mct at 10050000 {
>>               compatible = "none";
>>       };
>> diff --git a/arch/arm/boot/dts/exynos4210.dtsi
>> b/arch/arm/boot/dts/exynos4210.dtsi index 48ecd7a..40cd663 100644
>> --- a/arch/arm/boot/dts/exynos4210.dtsi
>> +++ b/arch/arm/boot/dts/exynos4210.dtsi
>> @@ -36,6 +36,34 @@
>>               reg = <0x10023CA0 0x20>;
>>       };
>>
>> +     cpus {
>> +             #address-cells = <1>;
>> +             #size-cells = <0>;
>> +             cpu at 0 {
>> +                     device_type = "cpu";
>> +                     compatible = "arm,cortex-a9";
>> +                     reg = <0>;
>> +                     clocks = <&clock 12>;
>> +                     clock-names = "cpu";
>> +
>> +                     operating-points = <
>> +                             200000  950000
>> +                             400000  975000
>> +                             500000  975000
>> +                             800000  1075000
>> +                             1000000 1150000
>> +                             1200000 1250000
>
> Please be consistent with "operating-points" definition. Here you use
> increasing order, when below you use decreasing one.

Okay, missed this one. Will fix in the next version.

Thanks,
Thomas.

>
>> +                     >;
>> +                     safe-opp = <800000 1075000>;
>> +             };
>> +
>> +             cpu at 1 {
>> +                     device_type = "cpu";
>> +                     compatible = "arm,cortex-a9";
>> +                     reg = <1>;
>> +             };
>> +     };
>> +
>>       gic: interrupt-controller at 10490000 {
>>               cpu-offset = <0x8000>;
>>       };
>> @@ -73,6 +101,13 @@
>>               compatible = "samsung,exynos4210-clock";
>>               reg = <0x10030000 0x20000>;
>>               #clock-cells = <1>;
>> +
>> +             arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7
>> 0 5 0 0>,
>> +                                   <1000000 1000000 0 3 7 3 4 1 7
>> 0 4 0 0>,
>> +                                   < 800000  800000 0 3 7 3 3 1 7
>> 0 3 0 0>,
>> +                                   < 500000  500000 0 3 7 3 3 1 7
>> 0 3 0 0>,
>> +                                   < 400000  400000 0 3 7 3 3 1 7
>> 0 3 0 0>,
>> +                                   < 200000  200000 0 1 3 1 1 1 0
>> 0 3 0 0>; };
>>
>>       pmu {
>> diff --git a/arch/arm/boot/dts/exynos4212.dtsi
>> b/arch/arm/boot/dts/exynos4212.dtsi index 94a43f9..2ea0f83 100644
>> --- a/arch/arm/boot/dts/exynos4212.dtsi
>> +++ b/arch/arm/boot/dts/exynos4212.dtsi
>> @@ -22,6 +22,23 @@
>>  / {
>>       compatible = "samsung,exynos4212";
>>
>> +     clock: clock-controller at 10030000 {
>> +             arm-frequency-table = <1500000 1500000 0 3 7 0 6 1 2
>> 0 6 2 0>,
>> +                                   <1400000 1400000 0 3 7 0 6 1 2
>> 0 6 2 0>,
>> +                                   <1300000 1300000 0 3 7 0 5 1 2
>> 0 5 2 0>,
>> +                                   <1200000 1200000 0 3 7 0 5 1 2
>> 0 5 2 0>,
>> +                                   <1100000 1100000 0 3 6 0 4 1 2
>> 0 4 2 0>,
>> +                                   <1000000 1000000 0 2 5 0 4 1 1
>> 0 4 2 0>,
>> +                                   < 900000  900000 0 2 5 0 3 1 1
>> 0 3 2 0>,
>> +                                   < 800000  800000 0 2 5 0 3 1 1
>> 0 3 2 0>,
>> +                                   < 700000  700000 0 2 4 0 3 1 1
>> 0 3 2 0>,
>> +                                   < 600000  600000 0 2 4 0 3 1 1
>> 0 3 2 0>,
>> +                                   < 500000  500000 0 2 4 0 3 1 1
>> 0 3 2 0>,
>> +                                   < 400000  400000 0 2 4 0 3 1 1
>> 0 3 2 0>,
>> +                                   < 300000  300000 0 2 4 0 2 1 1
>> 0 3 2 0>,
>> +                                   < 200000  200000 0 1 3 0 1 1 1
>> 0 3 2 0>;
>> +     };
>> +
>>       gic: interrupt-controller at 10490000 {
>>               cpu-offset = <0x8000>;
>>       };
>> diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts
>> b/arch/arm/boot/dts/exynos4412-odroidx.dts index 12459b0..1c751f9
>> 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx.dts
>> +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts
>> @@ -22,6 +22,12 @@
>>               reg = <0x40000000 0x40000000>;
>>       };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck2_reg>;
>> +             };
>> +     };
>> +
>>       leds {
>>               compatible = "gpio-leds";
>>               led1 {
>> diff --git a/arch/arm/boot/dts/exynos4412-origen.dts
>> b/arch/arm/boot/dts/exynos4412-origen.dts index 388f035..36080e5
>> 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts
>> +++ b/arch/arm/boot/dts/exynos4412-origen.dts
>> @@ -27,6 +27,12 @@
>>               bootargs ="console=ttySAC2,115200";
>>       };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck2_reg>;
>> +             };
>> +     };
>> +
>>       firmware at 0203F000 {
>>               compatible = "samsung,secure-firmware";
>>               reg = <0x0203F000 0x1000>;
>> diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts
>> b/arch/arm/boot/dts/exynos4412-trats2.dts index 4f851cc..4a4d446
>> 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts
>> +++ b/arch/arm/boot/dts/exynos4412-trats2.dts
>> @@ -31,6 +31,12 @@
>>               bootargs = "console=ttySAC2,115200N8
>> root=/dev/mmcblk0p5 rootwait earlyprintk panic=5"; };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck2_reg>;
>> +             };
>> +     };
>> +
>>       firmware at 0204F000 {
>>               compatible = "samsung,secure-firmware";
>>               reg = <0x0204F000 0x1000>;
>> diff --git a/arch/arm/boot/dts/exynos4412.dtsi
>> b/arch/arm/boot/dts/exynos4412.dtsi index 87b339c..7e9eca7 100644
>> --- a/arch/arm/boot/dts/exynos4412.dtsi
>> +++ b/arch/arm/boot/dts/exynos4412.dtsi
>> @@ -22,6 +22,36 @@
>>  / {
>>       compatible = "samsung,exynos4412";
>>
>> +     cpus {
>> +             cpu at 2 {
>> +                     device_type = "cpu";
>> +                     compatible = "arm,cortex-a9";
>> +                     reg = <2>;
>> +             };
>> +             cpu at 3 {
>> +                     device_type = "cpu";
>> +                     compatible = "arm,cortex-a9";
>> +                     reg = <3>;
>> +             };
>> +     };
>> +
>> +     clock: clock-controller at 10030000 {
>> +             arm-frequency-table = <1500000 1500000 0 3 7 0 6 1 2
>> 0 6 0 7>,
>> +                                   <1400000 1400000 0 3 7 0 6 1 2
>> 0 6 0 6>,
>> +                                   <1300000 1300000 0 3 7 0 5 1 2
>> 0 5 0 6>,
>> +                                   <1200000 1200000 0 3 7 0 5 1 2
>> 0 5 0 5>,
>> +                                   <1100000 1100000 0 3 6 0 4 1 2
>> 0 4 0 5>,
>> +                                   <1000000 1000000 0 2 5 0 4 1 1
>> 0 4 0 4>,
>> +                                   < 900000  900000 0 2 5 0 3 1 1
>> 0 3 0 4>,
>> +                                   < 800000  800000 0 2 5 0 3 1 1
>> 0 3 0 3>,
>> +                                   < 700000  700000 0 2 4 0 3 1 1
>> 0 3 0 3>,
>> +                                   < 600000  600000 0 2 4 0 3 1 1
>> 0 3 0 2>,
>> +                                   < 500000  500000 0 2 4 0 3 1 1
>> 0 3 0 2>,
>> +                                   < 400000  400000 0 2 4 0 3 1 1
>> 0 3 0 1>,
>> +                                   < 300000  300000 0 2 4 0 2 1 1
>> 0 3 0 1>,
>> +                                   < 200000  200000 0 1 3 0 1 1 1
>> 0 3 0 0>;
>> +     };
>> +
>>       gic: interrupt-controller at 10490000 {
>>               cpu-offset = <0x4000>;
>>       };
>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi
>> b/arch/arm/boot/dts/exynos4x12.dtsi index 5c412aa..47e2195 100644
>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>> @@ -31,6 +31,41 @@
>>               mshc0 = &mshc_0;
>>       };
>>
>> +     cpus {
>> +             #address-cells = <1>;
>> +             #size-cells = <0>;
>> +             cpu at 0 {
>> +                     device_type = "cpu";
>> +                     compatible = "arm,cortex-a9";
>> +                     reg = <0>;
>> +                     clocks = <&clock 12>;
>> +                     clock-names = "cpu";
>> +
>> +                     operating-points = <
>> +                             1400000 1350000
>> +                             1300000 1287500
>> +                             1200000 1250000
>> +                             1100000 1187500
>> +                             1000000 1137500
>> +                              900000 1087500
>> +                              800000 1037500
>> +                              700000 1000000
>> +                              600000  987500
>> +                              500000  950000
>> +                              400000  925000
>> +                              300000  900000
>> +                              200000  900000
>> +                     >;
>> +                     clock-latency = <200000>;
>> +                     safe-opp = <800000 1037500>;
>> +             };
>> +             cpu at 1 {
>> +                     device_type = "cpu";
>> +                     compatible = "arm,cortex-a9";
>> +                     reg = <1>;
>> +             };
>> +     };
>> +
>>       pd_isp: isp-power-domain at 10023CA0 {
>>               compatible = "samsung,exynos4210-pd";
>>               reg = <0x10023CA0 0x20>;
>> diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts
>> b/arch/arm/boot/dts/exynos5250-arndale.dts index b42e658..4716eef
>> 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts
>> +++ b/arch/arm/boot/dts/exynos5250-arndale.dts
>> @@ -25,6 +25,12 @@
>>               bootargs = "console=ttySAC2,115200";
>>       };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck2_reg>;
>> +             };
>> +     };
>> +
>>       codec at 11000000 {
>>               samsung,mfc-r = <0x43000000 0x800000>;
>>               samsung,mfc-l = <0x51000000 0x800000>;
>> diff --git a/arch/arm/boot/dts/exynos5250-cros-common.dtsi
>> b/arch/arm/boot/dts/exynos5250-cros-common.dtsi index
>> 2c1560d..4bde756 100644 ---
>> a/arch/arm/boot/dts/exynos5250-cros-common.dtsi +++
>> b/arch/arm/boot/dts/exynos5250-cros-common.dtsi @@ -19,6 +19,12 @@
>>       chosen {
>>       };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck2_reg>;
>> +             };
>> +     };
>> +
>>       pinctrl at 11400000 {
>>               /*
>>                * Disabled pullups since external part has its own
>> pullups and diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts
>> b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 5c1b7d9..7c228e2
>> 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
>> +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
>> @@ -27,6 +27,12 @@
>>               bootargs = "root=/dev/ram0 rw ramdisk=8192
>> initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; };
>>
>> +     cpus {
>> +             cpu at 0 {
>> +                     cpu0-supply = <&buck2_reg>;
>> +             };
>> +     };
>> +
>>       i2c at 12C60000 {
>>               samsung,i2c-sda-delay = <100>;
>>               samsung,i2c-max-bus-freq = <20000>;
>> diff --git a/arch/arm/boot/dts/exynos5250.dtsi
>> b/arch/arm/boot/dts/exynos5250.dtsi index b7dec41..d2f98dc 100644
>> --- a/arch/arm/boot/dts/exynos5250.dtsi
>> +++ b/arch/arm/boot/dts/exynos5250.dtsi
>> @@ -61,6 +61,30 @@
>>                       compatible = "arm,cortex-a15";
>>                       reg = <0>;
>>                       clock-frequency = <1700000000>;
>> +
>> +                     clocks = <&clock 12>;
>> +                     clock-names = "cpu";
>> +
>> +                     operating-points = <
>> +                             1700000 1300000
>> +                             1600000 1250000
>> +                             1500000 1225000
>> +                             1400000 1200000
>> +                             1300000 1150000
>> +                             1200000 1125000
>> +                             1100000 1100000
>> +                             1000000 1075000
>> +                              900000 1050000
>> +                              800000 1025000
>> +                              700000 1012500
>> +                              600000 1000000
>> +                              500000  975000
>> +                              400000  950000
>> +                              300000  937500
>> +                              200000  925000
>> +                     >;
>> +                     clock-latency = <200000>;
>> +                     safe-opp = <800000 1025000>;
>>               };
>>               cpu at 1 {
>>                       device_type = "cpu";
>> @@ -84,7 +108,24 @@
>>               compatible = "samsung,exynos5250-clock";
>>               reg = <0x10010000 0x30000>;
>>               #clock-cells = <1>;
>> -     };
>> +
>> +             arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5
>> 0 0 2 0>,
>> +                                   <1600000 1600000 0 3 7 7 7 1 4
>> 0 0 2 0>,
>> +                                   <1500000 1500000 0 2 7 7 7 1 4
>> 0 0 2 0>,
>> +                                   <1400000 1400000 0 2 7 7 6 1 4
>> 0 0 2 0>,
>> +                                   <1300000 1300000 0 2 7 7 6 1 3
>> 0 0 2 0>,
>> +                                   <1200000 1200000 0 2 7 7 5 1 3
>> 0 0 2 0>,
>> +                                   <1100000 1100000 0 3 7 7 5 1 3
>> 0 0 2 0>,
>> +                                   <1000000 1000000 0 1 7 7 4 1 2
>> 0 0 2 0>,
>> +                                   < 900000  900000 0 1 7 7 4 1 2
>> 0 0 2 0>,
>> +                                   < 800000  800000 0 1 7 7 4 1 2
>> 0 0 2 0>,
>> +                                   < 700000  700000 0 1 7 7 3 1 1
>> 0 0 2 0>,
>> +                                   < 600000  600000 0 1 7 7 3 1 1
>> 0 0 2 0>,
>> +                                   < 500000  500000 0 1 7 7 2 1 1
>> 0 0 2 0>,
>> +                                   < 400000  400000 0 1 7 7 2 1 1
>> 0 0 2 0>,
>> +                                   < 300000  300000 0 1 7 7 1 1 1
>> 0 0 2 0>,
>> +                                   < 200000  200000 0 1 7 7 1 1 1
>> 0 0 2 0>;
>> +     };
>>
>>       clock_audss: audss-clock-controller at 3810000 {
>>               compatible = "samsung,exynos5250-audss-clock";
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-01-20  7:47   ` Lukasz Majewski
@ 2014-01-21  7:52     ` Thomas Abraham
  2014-01-21 10:38       ` Lukasz Majewski
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 20, 2014 at 1:17 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> With the addition of the new Samsung specific cpu-clock type, the
>> arm clock can be represented as a cpu-clock type and the independent
>> clock blocks that made up the arm clock can be removed.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
>>  drivers/clk/samsung/clk-exynos4.c                  |   11 +++++------
>>  drivers/clk/samsung/clk-exynos5250.c               |    8 ++++----
>>  include/dt-bindings/clock/exynos5250.h             |    1 +
>>  4 files changed, 11 insertions(+), 10 deletions(-)
>>
>> diff --git
>> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt index
>> 99eae9c..acf867a 100644 ---
>> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt +++
>> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt @@
>> -38,6 +38,7 @@ clock which they consume. ----------------------------
>>    fin_pll            1
>> +  armclk             12
>>
>>    [Clock Gate for Special Clocks]
>>
>> diff --git a/drivers/clk/samsung/clk-exynos4.c
>> b/drivers/clk/samsung/clk-exynos4.c index 010f071..efcf4a3 100644
>> --- a/drivers/clk/samsung/clk-exynos4.c
>> +++ b/drivers/clk/samsung/clk-exynos4.c
>> @@ -437,8 +437,6 @@ static struct samsung_mux_clock
>> exynos4x12_mux_clks[] __initdata = {
>>  /* list of divider clocks supported in all exynos4 soc's */
>>  static struct samsung_div_clock exynos4_div_clks[] __initdata = {
>> -     DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3),
>> -     DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3),
>>       DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
>>       DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
>>       DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
>> @@ -484,8 +482,8 @@ static struct samsung_div_clock
>> exynos4_div_clks[] __initdata = { DIV(0, "div_spi_pre2", "div_spi2",
>> DIV_PERIL2, 8, 8), DIV(0, "div_audio1", "mout_audio1", DIV_PERIL4, 0,
>> 4), DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
>> -     DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
>> -     DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
>> 3),
>> +     DIV_F(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
>> 3,
>> +                     CLK_GET_RATE_NOCACHE, 0),
>>       DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
>>                       CLK_SET_RATE_PARENT, 0),
>>       DIV_F(0, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
>> @@ -870,7 +868,6 @@ static struct samsung_gate_clock
>> exynos4x12_gate_clks[] __initdata = {
>>  static struct samsung_clock_alias exynos4_aliases[] __initdata = {
>>       ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
>> -     ALIAS(CLK_ARM_CLK, NULL, "armclk"),
>>       ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"),
>>  };
>>
>> @@ -1125,12 +1122,14 @@ static void __init exynos4_clk_init(struct
>> device_node *np, samsung_clk_register_alias(exynos4_aliases,
>>                       ARRAY_SIZE(exynos4_aliases));
>>
>> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
>> reg_base); +
>
> I've got some doubts about allowing only the "mout_apll" clock to be the
> only parent for armclk Samsung clock.
>
> For the Exynos4412 it is also valid to have SCLK_MPLL_USER_C [*] as a
> parent for this clock.
>
> The problem is that you are reparenting the armclk to [*] with the
> register modification - no CCF involved.

The MUX_CORE mux is part of the larger cpu clock type and not
registered as a separate mux clock with CCF. So I would like to know
if there are any potential issues you see if this mux clock is
internally managed within the set_rate of the larger cpu clock type.

>
> I just would like to know if this is yours design decision or
> something, that we have overlooked in the v1 of this patch series.

I did overlook this one. This will be fixed in the next version by
ensuring that the dividers for SCLK_HPM clock will be updated only if
mout_apll is the parent of the MUX_HPM clock mux.

Thanks,
Thomas.

>
>>       pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
>>               "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk =
>> %ld\n", exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
>>               _get_rate("sclk_apll"),
>> _get_rate("sclk_mpll"), _get_rate("sclk_epll"),
>> _get_rate("sclk_vpll"),
>> -             _get_rate("arm_clk"));
>> +             _get_rate("armclk"));
>>  }
>>
>>
>> diff --git a/drivers/clk/samsung/clk-exynos5250.c
>> b/drivers/clk/samsung/clk-exynos5250.c index ff4beeb..487be36 100644
>> --- a/drivers/clk/samsung/clk-exynos5250.c
>> +++ b/drivers/clk/samsung/clk-exynos5250.c
>> @@ -298,9 +298,8 @@ static struct samsung_div_clock
>> exynos5250_div_clks[] __initdata = { /*
>>        * CMU_CPU
>>        */
>> -     DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
>> -     DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
>> -     DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3, "armclk"),
>> +     DIV_F(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
>> +                     CLK_GET_RATE_NOCACHE, 0),
>>
>>       /*
>>        * CMU_TOP
>> @@ -684,8 +683,9 @@ static void __init exynos5250_clk_init(struct
>> device_node *np) ARRAY_SIZE(exynos5250_div_clks));
>>       samsung_clk_register_gate(exynos5250_gate_clks,
>>                       ARRAY_SIZE(exynos5250_gate_clks));
>> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
>> reg_base);
>>       pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
>> -                     _get_rate("div_arm2"));
>> +                     _get_rate("armclk"));
>>  }
>>  CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock",
>> exynos5250_clk_init); diff --git
>> a/include/dt-bindings/clock/exynos5250.h
>> b/include/dt-bindings/clock/exynos5250.h index 922f2dc..59a10fb
>> 100644 --- a/include/dt-bindings/clock/exynos5250.h +++
>> b/include/dt-bindings/clock/exynos5250.h @@ -21,6 +21,7 @@
>>  #define CLK_FOUT_CPLL                6
>>  #define CLK_FOUT_EPLL                7
>>  #define CLK_FOUT_VPLL                8
>> +#define CLK_ARM_CLK          12
>>
>>  /* gate for special clocks (sclk) */
>>  #define CLK_SCLK_CAM_BAYER   128
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-01-20  8:08   ` Lukasz Majewski
@ 2014-01-21  8:08     ` Thomas Abraham
  2014-01-21  8:27       ` Lukasz Majewski
  2014-02-05 10:21     ` Thomas Abraham
  1 sibling, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21  8:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Mon, Jan 20, 2014 at 1:38 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched
>> over to use cpufreq-cpu0 driver for cpufreq functionality. So the
>> Exynos specific cpufreq drivers for these platforms can be removed.
>>
>> Cc: Kukjin Kim <kgene.kim@samsung.com>
>> Cc: Jaecheol Lee <jc.lee@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  drivers/cpufreq/Kconfig.arm          |   36 ----
>>  drivers/cpufreq/Makefile             |    4 -
>>  drivers/cpufreq/exynos-cpufreq.c     |  292
>> ----------------------------------
>> drivers/cpufreq/exynos-cpufreq.h     |   91 -----------
>> drivers/cpufreq/exynos4210-cpufreq.c |  157 ------------------
>> drivers/cpufreq/exynos4x12-cpufreq.c |  211 ------------------------
>> drivers/cpufreq/exynos5250-cpufreq.c |  183 --------------------- 7
>> files changed, 0 insertions(+), 974 deletions(-) delete mode 100644
>> drivers/cpufreq/exynos-cpufreq.c delete mode 100644
>> drivers/cpufreq/exynos-cpufreq.h delete mode 100644
>> drivers/cpufreq/exynos4210-cpufreq.c delete mode 100644
>> drivers/cpufreq/exynos4x12-cpufreq.c delete mode 100644
>> drivers/cpufreq/exynos5250-cpufreq.c
>>
>> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
>> index 3129749..704656d 100644
>> --- a/drivers/cpufreq/Kconfig.arm
>> +++ b/drivers/cpufreq/Kconfig.arm
>> @@ -16,42 +16,6 @@ config ARM_DT_BL_CPUFREQ
>>         This enables probing via DT for Generic CPUfreq driver for
>> ARM big.LITTLE platform. This gets frequency tables from DT.
>>
>> -config ARM_EXYNOS_CPUFREQ
>> -     bool
>> -
>> -config ARM_EXYNOS4210_CPUFREQ
>> -     bool "SAMSUNG EXYNOS4210"
>> -     depends on CPU_EXYNOS4210
>> -     default y
>> -     select ARM_EXYNOS_CPUFREQ
>> -     help
>> -       This adds the CPUFreq driver for Samsung EXYNOS4210
>> -       SoC (S5PV310 or S5PC210).
>> -
>> -       If in doubt, say N.
>> -
>> -config ARM_EXYNOS4X12_CPUFREQ
>> -     bool "SAMSUNG EXYNOS4x12"
>> -     depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
>> -     default y
>> -     select ARM_EXYNOS_CPUFREQ
>> -     help
>> -       This adds the CPUFreq driver for Samsung EXYNOS4X12
>> -       SoC (EXYNOS4212 or EXYNOS4412).
>> -
>> -       If in doubt, say N.
>> -
>> -config ARM_EXYNOS5250_CPUFREQ
>> -     bool "SAMSUNG EXYNOS5250"
>> -     depends on SOC_EXYNOS5250
>> -     default y
>> -     select ARM_EXYNOS_CPUFREQ
>> -     help
>> -       This adds the CPUFreq driver for Samsung EXYNOS5250
>> -       SoC.
>> -
>> -       If in doubt, say N.
>> -
>>  config ARM_EXYNOS5440_CPUFREQ
>>       bool "SAMSUNG EXYNOS5440"
>>       depends on SOC_EXYNOS5440
>> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
>> index 7494565..3abfe05 100644
>> --- a/drivers/cpufreq/Makefile
>> +++ b/drivers/cpufreq/Makefile
>> @@ -49,10 +49,6 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ)            +=
>> arm_big_little_dt.o
>>  obj-$(CONFIG_ARCH_DAVINCI_DA850)     += davinci-cpufreq.o
>>  obj-$(CONFIG_UX500_SOC_DB8500)               += dbx500-cpufreq.o
>> -obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)     += exynos-cpufreq.o
>> -obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
>> -obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
>> -obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
>>  obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
>>  obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)   += highbank-cpufreq.o
>>  obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)              += imx6q-cpufreq.o
>> diff --git a/drivers/cpufreq/exynos-cpufreq.c
>> b/drivers/cpufreq/exynos-cpufreq.c deleted file mode 100644
>> index fcd2914..0000000
>> --- a/drivers/cpufreq/exynos-cpufreq.c
>> +++ /dev/null
>> @@ -1,292 +0,0 @@
>> -/*
>> - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
>> - *           http://www.samsung.com
>> - *
>> - * EXYNOS - CPU frequency scaling support for EXYNOS series
>> - *
>> - * 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.
>> -*/
>> -
>> -#include <linux/kernel.h>
>> -#include <linux/err.h>
>> -#include <linux/clk.h>
>> -#include <linux/io.h>
>> -#include <linux/slab.h>
>> -#include <linux/regulator/consumer.h>
>> -#include <linux/cpufreq.h>
>> -#include <linux/suspend.h>
>> -#include <linux/platform_device.h>
>> -
>> -#include <plat/cpu.h>
>> -
>> -#include "exynos-cpufreq.h"
>> -
>> -static struct exynos_dvfs_info *exynos_info;
>> -
>> -static struct regulator *arm_regulator;
>> -
>> -static unsigned int locking_frequency;
>> -static bool frequency_locked;
>> -static DEFINE_MUTEX(cpufreq_lock);
>> -
>> -static int exynos_cpufreq_get_index(unsigned int freq)
>> -{
>> -     struct cpufreq_frequency_table *freq_table =
>> exynos_info->freq_table;
>> -     int index;
>> -
>> -     for (index = 0;
>> -             freq_table[index].frequency != CPUFREQ_TABLE_END;
>> index++)
>> -             if (freq_table[index].frequency == freq)
>> -                     break;
>> -
>> -     if (freq_table[index].frequency == CPUFREQ_TABLE_END)
>> -             return -EINVAL;
>> -
>> -     return index;
>> -}
>> -
>> -static int exynos_cpufreq_scale(unsigned int target_freq)
>> -{
>> -     struct cpufreq_frequency_table *freq_table =
>> exynos_info->freq_table;
>> -     unsigned int *volt_table = exynos_info->volt_table;
>> -     struct cpufreq_policy *policy = cpufreq_cpu_get(0);
>> -     unsigned int arm_volt, safe_arm_volt = 0;
>> -     unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
>> -     unsigned int old_freq;
>> -     int index, old_index;
>> -     int ret = 0;
>> -
>> -     old_freq = policy->cur;
>> -
>> -     /*
>> -      * The policy max have been changed so that we cannot get
>> proper
>> -      * old_index with cpufreq_frequency_table_target(). Thus,
>> ignore
>> -      * policy and get the index from the raw frequency table.
>> -      */
>> -     old_index = exynos_cpufreq_get_index(old_freq);
>> -     if (old_index < 0) {
>> -             ret = old_index;
>> -             goto out;
>> -     }
>> -
>> -     index = exynos_cpufreq_get_index(target_freq);
>> -     if (index < 0) {
>> -             ret = index;
>> -             goto out;
>> -     }
>> -
>> -     /*
>> -      * ARM clock source will be changed APLL to MPLL temporary
>> -      * To support this level, need to control regulator for
>> -      * required voltage level
>> -      */
>> -     if (exynos_info->need_apll_change != NULL) {
>> -             if (exynos_info->need_apll_change(old_index, index)
>> &&
>> -                (freq_table[index].frequency < mpll_freq_khz) &&
>> -                (freq_table[old_index].frequency < mpll_freq_khz))
>> -                     safe_arm_volt =
>> volt_table[exynos_info->pll_safe_idx];
>> -     }
>> -     arm_volt = volt_table[index];
>> -
>> -     /* When the new frequency is higher than current frequency */
>> -     if ((target_freq > old_freq) && !safe_arm_volt) {
>> -             /* Firstly, voltage up to increase frequency */
>> -             ret = regulator_set_voltage(arm_regulator, arm_volt,
>> arm_volt);
>> -             if (ret) {
>> -                     pr_err("%s: failed to set cpu voltage to
>> %d\n",
>> -                             __func__, arm_volt);
>> -                     return ret;
>> -             }
>> -     }
>> -
>> -     if (safe_arm_volt) {
>> -             ret = regulator_set_voltage(arm_regulator,
>> safe_arm_volt,
>> -                                   safe_arm_volt);
>> -             if (ret) {
>> -                     pr_err("%s: failed to set cpu voltage to
>> %d\n",
>> -                             __func__, safe_arm_volt);
>> -                     return ret;
>> -             }
>> -     }
>> -
>> -     exynos_info->set_freq(old_index, index);
>> -
>> -     /* When the new frequency is lower than current frequency */
>> -     if ((target_freq < old_freq) ||
>> -        ((target_freq > old_freq) && safe_arm_volt)) {
>> -             /* down the voltage after frequency change */
>> -             ret = regulator_set_voltage(arm_regulator, arm_volt,
>> -                             arm_volt);
>> -             if (ret) {
>> -                     pr_err("%s: failed to set cpu voltage to
>> %d\n",
>> -                             __func__, arm_volt);
>> -                     goto out;
>> -             }
>> -     }
>> -
>> -out:
>> -     cpufreq_cpu_put(policy);
>> -
>> -     return ret;
>> -}
>> -
>> -static int exynos_target(struct cpufreq_policy *policy, unsigned int
>> index) -{
>> -     struct cpufreq_frequency_table *freq_table =
>> exynos_info->freq_table;
>> -     int ret = 0;
>> -
>> -     mutex_lock(&cpufreq_lock);
>> -
>> -     if (frequency_locked)
>> -             goto out;
>> -
>> -     ret = exynos_cpufreq_scale(freq_table[index].frequency);
>> -
>> -out:
>> -     mutex_unlock(&cpufreq_lock);
>> -
>> -     return ret;
>> -}
>> -
>> -#ifdef CONFIG_PM
>> -static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
>> -{
>> -     return 0;
>> -}
>> -
>> -static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
>> -{
>> -     return 0;
>> -}
>> -#endif
>> -
>> -/**
>> - * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in
>> suspend-resume
>> - *                   context
>> - * @notifier
>> - * @pm_event
>> - * @v
>> - *
>> - * While frequency_locked == true, target() ignores every frequency
>> but
>> - * locking_frequency. The locking_frequency value is the initial
>> frequency,
>> - * which is set by the bootloader. In order to eliminate possible
>> - * inconsistency in clock values, we save and restore frequencies
>> during
>> - * suspend and resume and block CPUFREQ activities. Note that the
>> standard
>> - * suspend/resume cannot be used as they are too deep (syscore_ops)
>> for
>> - * regulator actions.
>> - */
>> -static int exynos_cpufreq_pm_notifier(struct notifier_block
>> *notifier,
>> -                                    unsigned long pm_event, void
>> *v) -{
>> -     int ret;
>> -
>> -     switch (pm_event) {
>> -     case PM_SUSPEND_PREPARE:
>> -             mutex_lock(&cpufreq_lock);
>> -             frequency_locked = true;
>> -             mutex_unlock(&cpufreq_lock);
>> -
>> -             ret = exynos_cpufreq_scale(locking_frequency);
>> -             if (ret < 0)
>> -                     return NOTIFY_BAD;
>> -
>> -             break;
>> -
>> -     case PM_POST_SUSPEND:
>> -             mutex_lock(&cpufreq_lock);
>> -             frequency_locked = false;
>> -             mutex_unlock(&cpufreq_lock);
>> -             break;
>> -     }
>> -
>> -     return NOTIFY_OK;
>> -}
>> -
>> -static struct notifier_block exynos_cpufreq_nb = {
>> -     .notifier_call = exynos_cpufreq_pm_notifier,
>> -};
>> -
>> -static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
>> -{
>> -     policy->clk = exynos_info->cpu_clk;
>> -     return cpufreq_generic_init(policy, exynos_info->freq_table,
>> 100000); -}
>> -
>> -static struct cpufreq_driver exynos_driver = {
>> -     .flags          = CPUFREQ_STICKY |
>> CPUFREQ_NEED_INITIAL_FREQ_CHECK,
>> -     .verify         =
>> cpufreq_generic_frequency_table_verify,
>> -     .target_index   = exynos_target,
>> -     .get            = cpufreq_generic_get,
>> -     .init           = exynos_cpufreq_cpu_init,
>> -     .exit           = cpufreq_generic_exit,
>> -     .name           = "exynos_cpufreq",
>> -     .attr           = cpufreq_generic_attr,
>> -#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
>> -     .boost_supported = true,
>> -#endif
>> -#ifdef CONFIG_PM
>> -     .suspend        = exynos_cpufreq_suspend,
>> -     .resume         = exynos_cpufreq_resume,
>> -#endif
>> -};
>> -
>> -static int exynos_cpufreq_probe(struct platform_device *pdev)
>> -{
>> -     int ret = -EINVAL;
>> -
>> -     exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
>> -     if (!exynos_info)
>> -             return -ENOMEM;
>> -
>> -     if (soc_is_exynos4210())
>> -             ret = exynos4210_cpufreq_init(exynos_info);
>> -     else if (soc_is_exynos4212() || soc_is_exynos4412())
>> -             ret = exynos4x12_cpufreq_init(exynos_info);
>> -     else if (soc_is_exynos5250())
>> -             ret = exynos5250_cpufreq_init(exynos_info);
>> -     else
>> -             return 0;
>> -
>> -     if (ret)
>> -             goto err_vdd_arm;
>> -
>> -     if (exynos_info->set_freq == NULL) {
>> -             pr_err("%s: No set_freq function (ERR)\n", __func__);
>> -             goto err_vdd_arm;
>> -     }
>> -
>> -     arm_regulator = regulator_get(NULL, "vdd_arm");
>> -     if (IS_ERR(arm_regulator)) {
>> -             pr_err("%s: failed to get resource vdd_arm\n",
>> __func__);
>> -             goto err_vdd_arm;
>> -     }
>> -
>> -     locking_frequency = clk_get_rate(exynos_info->cpu_clk) /
>> 1000; -
>> -     register_pm_notifier(&exynos_cpufreq_nb);
>> -
>> -     if (cpufreq_register_driver(&exynos_driver)) {
>> -             pr_err("%s: failed to register cpufreq driver\n",
>> __func__);
>> -             goto err_cpufreq;
>> -     }
>> -
>> -     return 0;
>> -err_cpufreq:
>> -     unregister_pm_notifier(&exynos_cpufreq_nb);
>> -
>> -     regulator_put(arm_regulator);
>> -err_vdd_arm:
>> -     kfree(exynos_info);
>> -     return -EINVAL;
>> -}
>> -
>> -static struct platform_driver exynos_cpufreq_platdrv = {
>> -     .driver = {
>> -             .name   = "exynos-cpufreq",
>> -             .owner  = THIS_MODULE,
>> -     },
>> -     .probe = exynos_cpufreq_probe,
>> -};
>> -module_platform_driver(exynos_cpufreq_platdrv);
>> diff --git a/drivers/cpufreq/exynos-cpufreq.h
>> b/drivers/cpufreq/exynos-cpufreq.h deleted file mode 100644
>> index 3ddade8..0000000
>> --- a/drivers/cpufreq/exynos-cpufreq.h
>> +++ /dev/null
>> @@ -1,91 +0,0 @@
>> -/*
>> - * Copyright (c) 2010 Samsung Electronics Co., Ltd.
>> - *           http://www.samsung.com
>> - *
>> - * EXYNOS - CPUFreq 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.
>> -*/
>> -
>> -enum cpufreq_level_index {
>> -     L0, L1, L2, L3, L4,
>> -     L5, L6, L7, L8, L9,
>> -     L10, L11, L12, L13, L14,
>> -     L15, L16, L17, L18, L19,
>> -     L20,
>> -};
>> -
>> -#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m,
>> p, s) \
>> -     { \
>> -             .freq = (f) * 1000, \
>> -             .clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3)
>> << 12 | \
>> -                     (a4) << 16 | (a5) << 20 | (a6) << 24 | (a7)
>> << 28), \
>> -             .clk_div_cpu1 = (b0 << 0 | b1 << 4 | b2 << 8), \
>> -             .mps = ((m) << 16 | (p) << 8 | (s)), \
>> -     }
>> -
>> -struct apll_freq {
>> -     unsigned int freq;
>> -     u32 clk_div_cpu0;
>> -     u32 clk_div_cpu1;
>> -     u32 mps;
>> -};
>> -
>> -struct exynos_dvfs_info {
>> -     unsigned long   mpll_freq_khz;
>> -     unsigned int    pll_safe_idx;
>> -     struct clk      *cpu_clk;
>> -     unsigned int    *volt_table;
>> -     struct cpufreq_frequency_table  *freq_table;
>> -     void (*set_freq)(unsigned int, unsigned int);
>> -     bool (*need_apll_change)(unsigned int, unsigned int);
>> -};
>> -
>> -#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
>> -extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
>> -#else
>> -static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info
>> *info) -{
>> -     return -EOPNOTSUPP;
>> -}
>> -#endif
>> -#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
>> -extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
>> -#else
>> -static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info
>> *info) -{
>> -     return -EOPNOTSUPP;
>> -}
>> -#endif
>> -#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
>> -extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
>> -#else
>> -static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info
>> *info) -{
>> -     return -EOPNOTSUPP;
>> -}
>> -#endif
>> -
>> -#include <plat/cpu.h>
>> -#include <mach/map.h>
>> -
>> -#define EXYNOS4_CLKSRC_CPU                   (S5P_VA_CMU +
>> 0x14200) -#define EXYNOS4_CLKMUX_STATCPU
>> (S5P_VA_CMU + 0x14400) -
>> -#define EXYNOS4_CLKDIV_CPU                   (S5P_VA_CMU +
>> 0x14500) -#define EXYNOS4_CLKDIV_CPU1
>> (S5P_VA_CMU + 0x14504) -#define
>> EXYNOS4_CLKDIV_STATCPU                        (S5P_VA_CMU + 0x14600)
>> -#define EXYNOS4_CLKDIV_STATCPU1                      (S5P_VA_CMU +
>> 0x14604) - -#define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT  (16)
>> -#define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK  (0x7 <<
>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT) -
>> -#define EXYNOS5_APLL_LOCK                    (S5P_VA_CMU +
>> 0x00000) -#define EXYNOS5_APLL_CON0
>> (S5P_VA_CMU + 0x00100) -#define
>> EXYNOS5_CLKMUX_STATCPU                        (S5P_VA_CMU + 0x00400)
>> -#define EXYNOS5_CLKDIV_CPU0                  (S5P_VA_CMU +
>> 0x00500) -#define EXYNOS5_CLKDIV_CPU1
>> (S5P_VA_CMU + 0x00504) -#define
>> EXYNOS5_CLKDIV_STATCPU0                       (S5P_VA_CMU + 0x00600)
>> -#define EXYNOS5_CLKDIV_STATCPU1                      (S5P_VA_CMU +
>> 0x00604) diff --git a/drivers/cpufreq/exynos4210-cpufreq.c
>> b/drivers/cpufreq/exynos4210-cpufreq.c deleted file mode 100644 index
>> 40d84c4..0000000 --- a/drivers/cpufreq/exynos4210-cpufreq.c
>> +++ /dev/null @@ -1,157 +0,0 @@
>> -/*
>> - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
>> - *           http://www.samsung.com
>> - *
>> - * EXYNOS4210 - CPU frequency scaling 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.
>> -*/
>> -
>> -#include <linux/module.h>
>> -#include <linux/kernel.h>
>> -#include <linux/err.h>
>> -#include <linux/clk.h>
>> -#include <linux/io.h>
>> -#include <linux/slab.h>
>> -#include <linux/cpufreq.h>
>> -
>> -#include "exynos-cpufreq.h"
>> -
>> -static struct clk *cpu_clk;
>> -static struct clk *moutcore;
>> -static struct clk *mout_mpll;
>> -static struct clk *mout_apll;
>> -
>> -static unsigned int exynos4210_volt_table[] = {
>> -     1250000, 1150000, 1050000, 975000, 950000,
>> -};
>> -
>> -static struct cpufreq_frequency_table exynos4210_freq_table[] = {
>> -     {L0, 1200 * 1000},
>> -     {L1, 1000 * 1000},
>> -     {L2,  800 * 1000},
>> -     {L3,  500 * 1000},
>> -     {L4,  200 * 1000},
>> -     {0, CPUFREQ_TABLE_END},
>> -};
>> -
>> -static struct apll_freq apll_freq_4210[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> PCLK_DBG, APLL, RESERVED
>> -      * clock divider for COPY, HPM, RESERVED
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
>> -     APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
>> -     APLL_FREQ(800,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
>> -     APLL_FREQ(500,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
>> -     APLL_FREQ(200,  0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
>> -};
>> -
>> -static void exynos4210_set_clkdiv(unsigned int div_index)
>> -{
>> -     unsigned int tmp;
>> -
>> -     /* Change Divider - CPU0 */
>> -
>> -     tmp = apll_freq_4210[div_index].clk_div_cpu0;
>> -
>> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
>> -
>> -     do {
>> -             tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
>> -     } while (tmp & 0x1111111);
>> -
>> -     /* Change Divider - CPU1 */
>> -
>> -     tmp = apll_freq_4210[div_index].clk_div_cpu1;
>> -
>> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
>> -
>> -     do {
>> -             tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
>> -     } while (tmp & 0x11);
>> -}
>> -
>> -static void exynos4210_set_apll(unsigned int index)
>> -{
>> -     unsigned int tmp, freq = apll_freq_4210[index].freq;
>> -
>> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> -     clk_set_parent(moutcore, mout_mpll);
>> -
>> -     do {
>> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
>> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
>> -             tmp &= 0x7;
>> -     } while (tmp != 0x2);
>> -
>> -     clk_set_rate(mout_apll, freq * 1000);
>> -
>> -     /* MUX_CORE_SEL = APLL */
>> -     clk_set_parent(moutcore, mout_apll);
>> -
>> -     do {
>> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
>> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
>> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
>> -}
>> -
>> -static void exynos4210_set_frequency(unsigned int old_index,
>> -                                  unsigned int new_index)
>> -{
>> -     if (old_index > new_index) {
>> -             exynos4210_set_clkdiv(new_index);
>> -             exynos4210_set_apll(new_index);
>> -     } else if (old_index < new_index) {
>> -             exynos4210_set_apll(new_index);
>> -             exynos4210_set_clkdiv(new_index);
>> -     }
>> -}
>> -
>> -int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
>> -{
>> -     unsigned long rate;
>> -
>> -     cpu_clk = clk_get(NULL, "armclk");
>> -     if (IS_ERR(cpu_clk))
>> -             return PTR_ERR(cpu_clk);
>> -
>> -     moutcore = clk_get(NULL, "moutcore");
>> -     if (IS_ERR(moutcore))
>> -             goto err_moutcore;
>> -
>> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> -     if (IS_ERR(mout_mpll))
>> -             goto err_mout_mpll;
>> -
>> -     rate = clk_get_rate(mout_mpll) / 1000;
>> -
>> -     mout_apll = clk_get(NULL, "mout_apll");
>> -     if (IS_ERR(mout_apll))
>> -             goto err_mout_apll;
>> -
>> -     info->mpll_freq_khz = rate;
>> -     /* 800Mhz */
>> -     info->pll_safe_idx = L2;
>> -     info->cpu_clk = cpu_clk;
>> -     info->volt_table = exynos4210_volt_table;
>> -     info->freq_table = exynos4210_freq_table;
>> -     info->set_freq = exynos4210_set_frequency;
>> -
>> -     return 0;
>> -
>> -err_mout_apll:
>> -     clk_put(mout_mpll);
>> -err_mout_mpll:
>> -     clk_put(moutcore);
>> -err_moutcore:
>> -     clk_put(cpu_clk);
>> -
>> -     pr_debug("%s: failed initialization\n", __func__);
>> -     return -EINVAL;
>> -}
>> diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c
>> b/drivers/cpufreq/exynos4x12-cpufreq.c deleted file mode 100644
>> index 7c11ace..0000000
>> --- a/drivers/cpufreq/exynos4x12-cpufreq.c
>> +++ /dev/null
>> @@ -1,211 +0,0 @@
>> -/*
>> - * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
>> - *           http://www.samsung.com
>> - *
>> - * EXYNOS4X12 - CPU frequency scaling 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.
>> -*/
>> -
>> -#include <linux/module.h>
>> -#include <linux/kernel.h>
>> -#include <linux/err.h>
>> -#include <linux/clk.h>
>> -#include <linux/io.h>
>> -#include <linux/slab.h>
>> -#include <linux/cpufreq.h>
>> -
>> -#include "exynos-cpufreq.h"
>> -
>> -static struct clk *cpu_clk;
>> -static struct clk *moutcore;
>> -static struct clk *mout_mpll;
>> -static struct clk *mout_apll;
>> -
>> -static unsigned int exynos4x12_volt_table[] = {
>> -     1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
>> 1037500,
>> -     1000000,  987500,  975000,  950000,  925000,  900000,  900000
>> -};
>> -
>> -static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
>> -     {CPUFREQ_BOOST_FREQ, 1500 * 1000},
>
> Here, you are removing BOOST support for Exynos4412, without any code,
> which brings back this functionality in the new code.

Sorry, I did not notice this new feature in here.

>
> I'd propose adding new property to cpus node and during
> operating-points parsing mark the entry at the cpufreq_frequency_table
> accordingly.

Okay, would you be adding support for this or do you want me to do this?

Thanks,
Thomas.

>
>> -     {L1, 1400 * 1000},
>> -     {L2, 1300 * 1000},
>> -     {L3, 1200 * 1000},
>> -     {L4, 1100 * 1000},
>> -     {L5, 1000 * 1000},
>> -     {L6,  900 * 1000},
>> -     {L7,  800 * 1000},
>> -     {L8,  700 * 1000},
>> -     {L9,  600 * 1000},
>> -     {L10, 500 * 1000},
>> -     {L11, 400 * 1000},
>> -     {L12, 300 * 1000},
>> -     {L13, 200 * 1000},
>> -     {0, CPUFREQ_TABLE_END},
>> -};
>> -
>> -static struct apll_freq *apll_freq_4x12;
>> -
>> -static struct apll_freq apll_freq_4212[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> PCLK_DBG, APLL, CORE2
>> -      * clock divider for COPY, HPM, RESERVED
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
>> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
>> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
>> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
>> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
>> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
>> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
>> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
>> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
>> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
>> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
>> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
>> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
>> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
>> -};
>> -
>> -static struct apll_freq apll_freq_4412[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> PCLK_DBG, APLL, CORE2
>> -      * clock divider for COPY, HPM, CORES
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
>> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
>> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
>> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
>> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
>> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
>> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
>> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
>> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
>> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
>> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
>> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
>> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
>> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
>> -};
>> -
>> -static void exynos4x12_set_clkdiv(unsigned int div_index)
>> -{
>> -     unsigned int tmp;
>> -     unsigned int stat_cpu1;
>> -
>> -     /* Change Divider - CPU0 */
>> -
>> -     tmp = apll_freq_4x12[div_index].clk_div_cpu0;
>> -
>> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
>> -
>> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
>> -             cpu_relax();
>> -
>> -     /* Change Divider - CPU1 */
>> -     tmp = apll_freq_4x12[div_index].clk_div_cpu1;
>> -
>> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
>> -     if (soc_is_exynos4212())
>> -             stat_cpu1 = 0x11;
>> -     else
>> -             stat_cpu1 = 0x111;
>> -
>> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
>> -             cpu_relax();
>> -}
>> -
>> -static void exynos4x12_set_apll(unsigned int index)
>> -{
>> -     unsigned int tmp, freq = apll_freq_4x12[index].freq;
>> -
>> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> -     clk_set_parent(moutcore, mout_mpll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
>> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
>> -             tmp &= 0x7;
>> -     } while (tmp != 0x2);
>> -
>> -     clk_set_rate(mout_apll, freq * 1000);
>> -
>> -     /* MUX_CORE_SEL = APLL */
>> -     clk_set_parent(moutcore, mout_apll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
>> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
>> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
>> -}
>> -
>> -static void exynos4x12_set_frequency(unsigned int old_index,
>> -                               unsigned int new_index)
>> -{
>> -     if (old_index > new_index) {
>> -             exynos4x12_set_clkdiv(new_index);
>> -             exynos4x12_set_apll(new_index);
>> -     } else if (old_index < new_index) {
>> -             exynos4x12_set_apll(new_index);
>> -             exynos4x12_set_clkdiv(new_index);
>> -     }
>> -}
>> -
>> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
>> -{
>> -     unsigned long rate;
>> -
>> -     cpu_clk = clk_get(NULL, "armclk");
>> -     if (IS_ERR(cpu_clk))
>> -             return PTR_ERR(cpu_clk);
>> -
>> -     moutcore = clk_get(NULL, "moutcore");
>> -     if (IS_ERR(moutcore))
>> -             goto err_moutcore;
>> -
>> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> -     if (IS_ERR(mout_mpll))
>> -             goto err_mout_mpll;
>> -
>> -     rate = clk_get_rate(mout_mpll) / 1000;
>> -
>> -     mout_apll = clk_get(NULL, "mout_apll");
>> -     if (IS_ERR(mout_apll))
>> -             goto err_mout_apll;
>> -
>> -     if (soc_is_exynos4212())
>> -             apll_freq_4x12 = apll_freq_4212;
>> -     else
>> -             apll_freq_4x12 = apll_freq_4412;
>> -
>> -     info->mpll_freq_khz = rate;
>> -     /* 800Mhz */
>> -     info->pll_safe_idx = L7;
>> -     info->cpu_clk = cpu_clk;
>> -     info->volt_table = exynos4x12_volt_table;
>> -     info->freq_table = exynos4x12_freq_table;
>> -     info->set_freq = exynos4x12_set_frequency;
>> -
>> -     return 0;
>> -
>> -err_mout_apll:
>> -     clk_put(mout_mpll);
>> -err_mout_mpll:
>> -     clk_put(moutcore);
>> -err_moutcore:
>> -     clk_put(cpu_clk);
>> -
>> -     pr_debug("%s: failed initialization\n", __func__);
>> -     return -EINVAL;
>> -}
>> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
>> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
>> index 5f90b82..0000000
>> --- a/drivers/cpufreq/exynos5250-cpufreq.c
>> +++ /dev/null
>> @@ -1,183 +0,0 @@
>> -/*
>> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
>> - *           http://www.samsung.com
>> - *
>> - * EXYNOS5250 - CPU frequency scaling 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.
>> -*/
>> -
>> -#include <linux/module.h>
>> -#include <linux/kernel.h>
>> -#include <linux/err.h>
>> -#include <linux/clk.h>
>> -#include <linux/io.h>
>> -#include <linux/slab.h>
>> -#include <linux/cpufreq.h>
>> -
>> -#include <mach/map.h>
>> -
>> -#include "exynos-cpufreq.h"
>> -
>> -static struct clk *cpu_clk;
>> -static struct clk *moutcore;
>> -static struct clk *mout_mpll;
>> -static struct clk *mout_apll;
>> -
>> -static unsigned int exynos5250_volt_table[] = {
>> -     1300000, 1250000, 1225000, 1200000, 1150000,
>> -     1125000, 1100000, 1075000, 1050000, 1025000,
>> -     1012500, 1000000,  975000,  950000,  937500,
>> -     925000
>> -};
>> -
>> -static struct cpufreq_frequency_table exynos5250_freq_table[] = {
>> -     {L0, 1700 * 1000},
>> -     {L1, 1600 * 1000},
>> -     {L2, 1500 * 1000},
>> -     {L3, 1400 * 1000},
>> -     {L4, 1300 * 1000},
>> -     {L5, 1200 * 1000},
>> -     {L6, 1100 * 1000},
>> -     {L7, 1000 * 1000},
>> -     {L8,  900 * 1000},
>> -     {L9,  800 * 1000},
>> -     {L10, 700 * 1000},
>> -     {L11, 600 * 1000},
>> -     {L12, 500 * 1000},
>> -     {L13, 400 * 1000},
>> -     {L14, 300 * 1000},
>> -     {L15, 200 * 1000},
>> -     {0, CPUFREQ_TABLE_END},
>> -};
>> -
>> -static struct apll_freq apll_freq_5250[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG,
>> APLL, ARM2
>> -      * clock divider for COPY, HPM, RESERVED
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
>> -     APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
>> -     APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
>> -     APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
>> -     APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
>> -     APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
>> -     APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
>> -     APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
>> -     APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
>> -     APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
>> -     APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
>> -     APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
>> -     APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
>> -     APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
>> -     APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
>> -     APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
>> -};
>> -
>> -static void set_clkdiv(unsigned int div_index)
>> -{
>> -     unsigned int tmp;
>> -
>> -     /* Change Divider - CPU0 */
>> -
>> -     tmp = apll_freq_5250[div_index].clk_div_cpu0;
>> -
>> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
>> -
>> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
>> -             cpu_relax();
>> -
>> -     /* Change Divider - CPU1 */
>> -     tmp = apll_freq_5250[div_index].clk_div_cpu1;
>> -
>> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
>> -
>> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
>> -             cpu_relax();
>> -}
>> -
>> -static void set_apll(unsigned int index)
>> -{
>> -     unsigned int tmp;
>> -     unsigned int freq = apll_freq_5250[index].freq;
>> -
>> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> -     clk_set_parent(moutcore, mout_mpll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
>> -             tmp &= 0x7;
>> -     } while (tmp != 0x2);
>> -
>> -     clk_set_rate(mout_apll, freq * 1000);
>> -
>> -     /* MUX_CORE_SEL = APLL */
>> -     clk_set_parent(moutcore, mout_apll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
>> -             tmp &= (0x7 << 16);
>> -     } while (tmp != (0x1 << 16));
>> -}
>> -
>> -static void exynos5250_set_frequency(unsigned int old_index,
>> -                               unsigned int new_index)
>> -{
>> -     if (old_index > new_index) {
>> -             set_clkdiv(new_index);
>> -             set_apll(new_index);
>> -     } else if (old_index < new_index) {
>> -             set_apll(new_index);
>> -             set_clkdiv(new_index);
>> -     }
>> -}
>> -
>> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
>> -{
>> -     unsigned long rate;
>> -
>> -     cpu_clk = clk_get(NULL, "armclk");
>> -     if (IS_ERR(cpu_clk))
>> -             return PTR_ERR(cpu_clk);
>> -
>> -     moutcore = clk_get(NULL, "mout_cpu");
>> -     if (IS_ERR(moutcore))
>> -             goto err_moutcore;
>> -
>> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> -     if (IS_ERR(mout_mpll))
>> -             goto err_mout_mpll;
>> -
>> -     rate = clk_get_rate(mout_mpll) / 1000;
>> -
>> -     mout_apll = clk_get(NULL, "mout_apll");
>> -     if (IS_ERR(mout_apll))
>> -             goto err_mout_apll;
>> -
>> -     info->mpll_freq_khz = rate;
>> -     /* 800Mhz */
>> -     info->pll_safe_idx = L9;
>> -     info->cpu_clk = cpu_clk;
>> -     info->volt_table = exynos5250_volt_table;
>> -     info->freq_table = exynos5250_freq_table;
>> -     info->set_freq = exynos5250_set_frequency;
>> -
>> -     return 0;
>> -
>> -err_mout_apll:
>> -     clk_put(mout_mpll);
>> -err_mout_mpll:
>> -     clk_put(moutcore);
>> -err_moutcore:
>> -     clk_put(cpu_clk);
>> -
>> -     pr_err("%s: failed initialization\n", __func__);
>> -     return -EINVAL;
>> -}
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-01-21  8:08     ` Thomas Abraham
@ 2014-01-21  8:27       ` Lukasz Majewski
  0 siblings, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-21  8:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> Hi Lukasz,
> 
> On Mon, Jan 20, 2014 at 1:38 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched
> >> over to use cpufreq-cpu0 driver for cpufreq functionality. So the
> >> Exynos specific cpufreq drivers for these platforms can be removed.
> >>
> >> Cc: Kukjin Kim <kgene.kim@samsung.com>
> >> Cc: Jaecheol Lee <jc.lee@samsung.com>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> ---
> >>  drivers/cpufreq/Kconfig.arm          |   36 ----
> >>  drivers/cpufreq/Makefile             |    4 -
> >>  drivers/cpufreq/exynos-cpufreq.c     |  292
> >> ----------------------------------
> >> drivers/cpufreq/exynos-cpufreq.h     |   91 -----------
> >> drivers/cpufreq/exynos4210-cpufreq.c |  157 ------------------
> >> drivers/cpufreq/exynos4x12-cpufreq.c |  211
> >> ------------------------ drivers/cpufreq/exynos5250-cpufreq.c |
> >> 183 --------------------- 7 files changed, 0 insertions(+), 974
> >> deletions(-) delete mode 100644 drivers/cpufreq/exynos-cpufreq.c
> >> delete mode 100644 drivers/cpufreq/exynos-cpufreq.h delete mode
> >> 100644 drivers/cpufreq/exynos4210-cpufreq.c delete mode 100644
> >> drivers/cpufreq/exynos4x12-cpufreq.c delete mode 100644
> >> drivers/cpufreq/exynos5250-cpufreq.c
> >>
> >> diff --git a/drivers/cpufreq/Kconfig.arm
> >> b/drivers/cpufreq/Kconfig.arm index 3129749..704656d 100644
> >> --- a/drivers/cpufreq/Kconfig.arm
> >> +++ b/drivers/cpufreq/Kconfig.arm
> >> @@ -16,42 +16,6 @@ config ARM_DT_BL_CPUFREQ
> >>         This enables probing via DT for Generic CPUfreq driver for
> >> ARM big.LITTLE platform. This gets frequency tables from DT.
> >>
> >> -config ARM_EXYNOS_CPUFREQ
> >> -     bool
> >> -
> >> -config ARM_EXYNOS4210_CPUFREQ
> >> -     bool "SAMSUNG EXYNOS4210"
> >> -     depends on CPU_EXYNOS4210
> >> -     default y
> >> -     select ARM_EXYNOS_CPUFREQ
> >> -     help
> >> -       This adds the CPUFreq driver for Samsung EXYNOS4210
> >> -       SoC (S5PV310 or S5PC210).
> >> -
> >> -       If in doubt, say N.
> >> -
> >> -config ARM_EXYNOS4X12_CPUFREQ
> >> -     bool "SAMSUNG EXYNOS4x12"
> >> -     depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
> >> -     default y
> >> -     select ARM_EXYNOS_CPUFREQ
> >> -     help
> >> -       This adds the CPUFreq driver for Samsung EXYNOS4X12
> >> -       SoC (EXYNOS4212 or EXYNOS4412).
> >> -
> >> -       If in doubt, say N.
> >> -
> >> -config ARM_EXYNOS5250_CPUFREQ
> >> -     bool "SAMSUNG EXYNOS5250"
> >> -     depends on SOC_EXYNOS5250
> >> -     default y
> >> -     select ARM_EXYNOS_CPUFREQ
> >> -     help
> >> -       This adds the CPUFreq driver for Samsung EXYNOS5250
> >> -       SoC.
> >> -
> >> -       If in doubt, say N.
> >> -
> >>  config ARM_EXYNOS5440_CPUFREQ
> >>       bool "SAMSUNG EXYNOS5440"
> >>       depends on SOC_EXYNOS5440
> >> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> >> index 7494565..3abfe05 100644
> >> --- a/drivers/cpufreq/Makefile
> >> +++ b/drivers/cpufreq/Makefile
> >> @@ -49,10 +49,6 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ)            +=
> >> arm_big_little_dt.o
> >>  obj-$(CONFIG_ARCH_DAVINCI_DA850)     += davinci-cpufreq.o
> >>  obj-$(CONFIG_UX500_SOC_DB8500)               += dbx500-cpufreq.o
> >> -obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)     += exynos-cpufreq.o
> >> -obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
> >> -obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
> >> -obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
> >>  obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
> >>  obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)   += highbank-cpufreq.o
> >>  obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)              += imx6q-cpufreq.o
> >> diff --git a/drivers/cpufreq/exynos-cpufreq.c
> >> b/drivers/cpufreq/exynos-cpufreq.c deleted file mode 100644
> >> index fcd2914..0000000
> >> --- a/drivers/cpufreq/exynos-cpufreq.c
> >> +++ /dev/null
> >> @@ -1,292 +0,0 @@
> >> -/*
> >> - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
> >> - *           http://www.samsung.com
> >> - *
> >> - * EXYNOS - CPU frequency scaling support for EXYNOS series
> >> - *
> >> - * 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.
> >> -*/
> >> -
> >> -#include <linux/kernel.h>
> >> -#include <linux/err.h>
> >> -#include <linux/clk.h>
> >> -#include <linux/io.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/regulator/consumer.h>
> >> -#include <linux/cpufreq.h>
> >> -#include <linux/suspend.h>
> >> -#include <linux/platform_device.h>
> >> -
> >> -#include <plat/cpu.h>
> >> -
> >> -#include "exynos-cpufreq.h"
> >> -
> >> -static struct exynos_dvfs_info *exynos_info;
> >> -
> >> -static struct regulator *arm_regulator;
> >> -
> >> -static unsigned int locking_frequency;
> >> -static bool frequency_locked;
> >> -static DEFINE_MUTEX(cpufreq_lock);
> >> -
> >> -static int exynos_cpufreq_get_index(unsigned int freq)
> >> -{
> >> -     struct cpufreq_frequency_table *freq_table =
> >> exynos_info->freq_table;
> >> -     int index;
> >> -
> >> -     for (index = 0;
> >> -             freq_table[index].frequency != CPUFREQ_TABLE_END;
> >> index++)
> >> -             if (freq_table[index].frequency == freq)
> >> -                     break;
> >> -
> >> -     if (freq_table[index].frequency == CPUFREQ_TABLE_END)
> >> -             return -EINVAL;
> >> -
> >> -     return index;
> >> -}
> >> -
> >> -static int exynos_cpufreq_scale(unsigned int target_freq)
> >> -{
> >> -     struct cpufreq_frequency_table *freq_table =
> >> exynos_info->freq_table;
> >> -     unsigned int *volt_table = exynos_info->volt_table;
> >> -     struct cpufreq_policy *policy = cpufreq_cpu_get(0);
> >> -     unsigned int arm_volt, safe_arm_volt = 0;
> >> -     unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
> >> -     unsigned int old_freq;
> >> -     int index, old_index;
> >> -     int ret = 0;
> >> -
> >> -     old_freq = policy->cur;
> >> -
> >> -     /*
> >> -      * The policy max have been changed so that we cannot get
> >> proper
> >> -      * old_index with cpufreq_frequency_table_target(). Thus,
> >> ignore
> >> -      * policy and get the index from the raw frequency table.
> >> -      */
> >> -     old_index = exynos_cpufreq_get_index(old_freq);
> >> -     if (old_index < 0) {
> >> -             ret = old_index;
> >> -             goto out;
> >> -     }
> >> -
> >> -     index = exynos_cpufreq_get_index(target_freq);
> >> -     if (index < 0) {
> >> -             ret = index;
> >> -             goto out;
> >> -     }
> >> -
> >> -     /*
> >> -      * ARM clock source will be changed APLL to MPLL temporary
> >> -      * To support this level, need to control regulator for
> >> -      * required voltage level
> >> -      */
> >> -     if (exynos_info->need_apll_change != NULL) {
> >> -             if (exynos_info->need_apll_change(old_index, index)
> >> &&
> >> -                (freq_table[index].frequency < mpll_freq_khz) &&
> >> -                (freq_table[old_index].frequency < mpll_freq_khz))
> >> -                     safe_arm_volt =
> >> volt_table[exynos_info->pll_safe_idx];
> >> -     }
> >> -     arm_volt = volt_table[index];
> >> -
> >> -     /* When the new frequency is higher than current frequency */
> >> -     if ((target_freq > old_freq) && !safe_arm_volt) {
> >> -             /* Firstly, voltage up to increase frequency */
> >> -             ret = regulator_set_voltage(arm_regulator, arm_volt,
> >> arm_volt);
> >> -             if (ret) {
> >> -                     pr_err("%s: failed to set cpu voltage to
> >> %d\n",
> >> -                             __func__, arm_volt);
> >> -                     return ret;
> >> -             }
> >> -     }
> >> -
> >> -     if (safe_arm_volt) {
> >> -             ret = regulator_set_voltage(arm_regulator,
> >> safe_arm_volt,
> >> -                                   safe_arm_volt);
> >> -             if (ret) {
> >> -                     pr_err("%s: failed to set cpu voltage to
> >> %d\n",
> >> -                             __func__, safe_arm_volt);
> >> -                     return ret;
> >> -             }
> >> -     }
> >> -
> >> -     exynos_info->set_freq(old_index, index);
> >> -
> >> -     /* When the new frequency is lower than current frequency */
> >> -     if ((target_freq < old_freq) ||
> >> -        ((target_freq > old_freq) && safe_arm_volt)) {
> >> -             /* down the voltage after frequency change */
> >> -             ret = regulator_set_voltage(arm_regulator, arm_volt,
> >> -                             arm_volt);
> >> -             if (ret) {
> >> -                     pr_err("%s: failed to set cpu voltage to
> >> %d\n",
> >> -                             __func__, arm_volt);
> >> -                     goto out;
> >> -             }
> >> -     }
> >> -
> >> -out:
> >> -     cpufreq_cpu_put(policy);
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -static int exynos_target(struct cpufreq_policy *policy, unsigned
> >> int index) -{
> >> -     struct cpufreq_frequency_table *freq_table =
> >> exynos_info->freq_table;
> >> -     int ret = 0;
> >> -
> >> -     mutex_lock(&cpufreq_lock);
> >> -
> >> -     if (frequency_locked)
> >> -             goto out;
> >> -
> >> -     ret = exynos_cpufreq_scale(freq_table[index].frequency);
> >> -
> >> -out:
> >> -     mutex_unlock(&cpufreq_lock);
> >> -
> >> -     return ret;
> >> -}
> >> -
> >> -#ifdef CONFIG_PM
> >> -static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
> >> -{
> >> -     return 0;
> >> -}
> >> -
> >> -static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
> >> -{
> >> -     return 0;
> >> -}
> >> -#endif
> >> -
> >> -/**
> >> - * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in
> >> suspend-resume
> >> - *                   context
> >> - * @notifier
> >> - * @pm_event
> >> - * @v
> >> - *
> >> - * While frequency_locked == true, target() ignores every
> >> frequency but
> >> - * locking_frequency. The locking_frequency value is the initial
> >> frequency,
> >> - * which is set by the bootloader. In order to eliminate possible
> >> - * inconsistency in clock values, we save and restore frequencies
> >> during
> >> - * suspend and resume and block CPUFREQ activities. Note that the
> >> standard
> >> - * suspend/resume cannot be used as they are too deep
> >> (syscore_ops) for
> >> - * regulator actions.
> >> - */
> >> -static int exynos_cpufreq_pm_notifier(struct notifier_block
> >> *notifier,
> >> -                                    unsigned long pm_event, void
> >> *v) -{
> >> -     int ret;
> >> -
> >> -     switch (pm_event) {
> >> -     case PM_SUSPEND_PREPARE:
> >> -             mutex_lock(&cpufreq_lock);
> >> -             frequency_locked = true;
> >> -             mutex_unlock(&cpufreq_lock);
> >> -
> >> -             ret = exynos_cpufreq_scale(locking_frequency);
> >> -             if (ret < 0)
> >> -                     return NOTIFY_BAD;
> >> -
> >> -             break;
> >> -
> >> -     case PM_POST_SUSPEND:
> >> -             mutex_lock(&cpufreq_lock);
> >> -             frequency_locked = false;
> >> -             mutex_unlock(&cpufreq_lock);
> >> -             break;
> >> -     }
> >> -
> >> -     return NOTIFY_OK;
> >> -}
> >> -
> >> -static struct notifier_block exynos_cpufreq_nb = {
> >> -     .notifier_call = exynos_cpufreq_pm_notifier,
> >> -};
> >> -
> >> -static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
> >> -{
> >> -     policy->clk = exynos_info->cpu_clk;
> >> -     return cpufreq_generic_init(policy, exynos_info->freq_table,
> >> 100000); -}
> >> -
> >> -static struct cpufreq_driver exynos_driver = {
> >> -     .flags          = CPUFREQ_STICKY |
> >> CPUFREQ_NEED_INITIAL_FREQ_CHECK,
> >> -     .verify         =
> >> cpufreq_generic_frequency_table_verify,
> >> -     .target_index   = exynos_target,
> >> -     .get            = cpufreq_generic_get,
> >> -     .init           = exynos_cpufreq_cpu_init,
> >> -     .exit           = cpufreq_generic_exit,
> >> -     .name           = "exynos_cpufreq",
> >> -     .attr           = cpufreq_generic_attr,
> >> -#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
> >> -     .boost_supported = true,
> >> -#endif
> >> -#ifdef CONFIG_PM
> >> -     .suspend        = exynos_cpufreq_suspend,
> >> -     .resume         = exynos_cpufreq_resume,
> >> -#endif
> >> -};
> >> -
> >> -static int exynos_cpufreq_probe(struct platform_device *pdev)
> >> -{
> >> -     int ret = -EINVAL;
> >> -
> >> -     exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
> >> -     if (!exynos_info)
> >> -             return -ENOMEM;
> >> -
> >> -     if (soc_is_exynos4210())
> >> -             ret = exynos4210_cpufreq_init(exynos_info);
> >> -     else if (soc_is_exynos4212() || soc_is_exynos4412())
> >> -             ret = exynos4x12_cpufreq_init(exynos_info);
> >> -     else if (soc_is_exynos5250())
> >> -             ret = exynos5250_cpufreq_init(exynos_info);
> >> -     else
> >> -             return 0;
> >> -
> >> -     if (ret)
> >> -             goto err_vdd_arm;
> >> -
> >> -     if (exynos_info->set_freq == NULL) {
> >> -             pr_err("%s: No set_freq function (ERR)\n", __func__);
> >> -             goto err_vdd_arm;
> >> -     }
> >> -
> >> -     arm_regulator = regulator_get(NULL, "vdd_arm");
> >> -     if (IS_ERR(arm_regulator)) {
> >> -             pr_err("%s: failed to get resource vdd_arm\n",
> >> __func__);
> >> -             goto err_vdd_arm;
> >> -     }
> >> -
> >> -     locking_frequency = clk_get_rate(exynos_info->cpu_clk) /
> >> 1000; -
> >> -     register_pm_notifier(&exynos_cpufreq_nb);
> >> -
> >> -     if (cpufreq_register_driver(&exynos_driver)) {
> >> -             pr_err("%s: failed to register cpufreq driver\n",
> >> __func__);
> >> -             goto err_cpufreq;
> >> -     }
> >> -
> >> -     return 0;
> >> -err_cpufreq:
> >> -     unregister_pm_notifier(&exynos_cpufreq_nb);
> >> -
> >> -     regulator_put(arm_regulator);
> >> -err_vdd_arm:
> >> -     kfree(exynos_info);
> >> -     return -EINVAL;
> >> -}
> >> -
> >> -static struct platform_driver exynos_cpufreq_platdrv = {
> >> -     .driver = {
> >> -             .name   = "exynos-cpufreq",
> >> -             .owner  = THIS_MODULE,
> >> -     },
> >> -     .probe = exynos_cpufreq_probe,
> >> -};
> >> -module_platform_driver(exynos_cpufreq_platdrv);
> >> diff --git a/drivers/cpufreq/exynos-cpufreq.h
> >> b/drivers/cpufreq/exynos-cpufreq.h deleted file mode 100644
> >> index 3ddade8..0000000
> >> --- a/drivers/cpufreq/exynos-cpufreq.h
> >> +++ /dev/null
> >> @@ -1,91 +0,0 @@
> >> -/*
> >> - * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> >> - *           http://www.samsung.com
> >> - *
> >> - * EXYNOS - CPUFreq 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.
> >> -*/
> >> -
> >> -enum cpufreq_level_index {
> >> -     L0, L1, L2, L3, L4,
> >> -     L5, L6, L7, L8, L9,
> >> -     L10, L11, L12, L13, L14,
> >> -     L15, L16, L17, L18, L19,
> >> -     L20,
> >> -};
> >> -
> >> -#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2,
> >> m, p, s) \
> >> -     { \
> >> -             .freq = (f) * 1000, \
> >> -             .clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3)
> >> << 12 | \
> >> -                     (a4) << 16 | (a5) << 20 | (a6) << 24 | (a7)
> >> << 28), \
> >> -             .clk_div_cpu1 = (b0 << 0 | b1 << 4 | b2 << 8), \
> >> -             .mps = ((m) << 16 | (p) << 8 | (s)), \
> >> -     }
> >> -
> >> -struct apll_freq {
> >> -     unsigned int freq;
> >> -     u32 clk_div_cpu0;
> >> -     u32 clk_div_cpu1;
> >> -     u32 mps;
> >> -};
> >> -
> >> -struct exynos_dvfs_info {
> >> -     unsigned long   mpll_freq_khz;
> >> -     unsigned int    pll_safe_idx;
> >> -     struct clk      *cpu_clk;
> >> -     unsigned int    *volt_table;
> >> -     struct cpufreq_frequency_table  *freq_table;
> >> -     void (*set_freq)(unsigned int, unsigned int);
> >> -     bool (*need_apll_change)(unsigned int, unsigned int);
> >> -};
> >> -
> >> -#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
> >> -extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
> >> -#else
> >> -static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info
> >> *info) -{
> >> -     return -EOPNOTSUPP;
> >> -}
> >> -#endif
> >> -#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
> >> -extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
> >> -#else
> >> -static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info
> >> *info) -{
> >> -     return -EOPNOTSUPP;
> >> -}
> >> -#endif
> >> -#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
> >> -extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
> >> -#else
> >> -static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info
> >> *info) -{
> >> -     return -EOPNOTSUPP;
> >> -}
> >> -#endif
> >> -
> >> -#include <plat/cpu.h>
> >> -#include <mach/map.h>
> >> -
> >> -#define EXYNOS4_CLKSRC_CPU                   (S5P_VA_CMU +
> >> 0x14200) -#define EXYNOS4_CLKMUX_STATCPU
> >> (S5P_VA_CMU + 0x14400) -
> >> -#define EXYNOS4_CLKDIV_CPU                   (S5P_VA_CMU +
> >> 0x14500) -#define EXYNOS4_CLKDIV_CPU1
> >> (S5P_VA_CMU + 0x14504) -#define
> >> EXYNOS4_CLKDIV_STATCPU                        (S5P_VA_CMU +
> >> 0x14600) -#define EXYNOS4_CLKDIV_STATCPU1
> >> (S5P_VA_CMU + 0x14604) - -#define
> >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT  (16) -#define
> >> EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK  (0x7 <<
> >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT) - -#define
> >> EXYNOS5_APLL_LOCK                    (S5P_VA_CMU + 0x00000)
> >> -#define EXYNOS5_APLL_CON0 (S5P_VA_CMU + 0x00100) -#define
> >> EXYNOS5_CLKMUX_STATCPU                        (S5P_VA_CMU +
> >> 0x00400) -#define EXYNOS5_CLKDIV_CPU0                  (S5P_VA_CMU
> >> + 0x00500) -#define EXYNOS5_CLKDIV_CPU1
> >> (S5P_VA_CMU + 0x00504) -#define
> >> EXYNOS5_CLKDIV_STATCPU0                       (S5P_VA_CMU +
> >> 0x00600) -#define EXYNOS5_CLKDIV_STATCPU1
> >> (S5P_VA_CMU + 0x00604) diff --git
> >> a/drivers/cpufreq/exynos4210-cpufreq.c
> >> b/drivers/cpufreq/exynos4210-cpufreq.c deleted file mode 100644
> >> index 40d84c4..0000000 --- a/drivers/cpufreq/exynos4210-cpufreq.c
> >> +++ /dev/null @@ -1,157 +0,0 @@ -/*
> >> - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
> >> - *           http://www.samsung.com
> >> - *
> >> - * EXYNOS4210 - CPU frequency scaling 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.
> >> -*/
> >> -
> >> -#include <linux/module.h>
> >> -#include <linux/kernel.h>
> >> -#include <linux/err.h>
> >> -#include <linux/clk.h>
> >> -#include <linux/io.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/cpufreq.h>
> >> -
> >> -#include "exynos-cpufreq.h"
> >> -
> >> -static struct clk *cpu_clk;
> >> -static struct clk *moutcore;
> >> -static struct clk *mout_mpll;
> >> -static struct clk *mout_apll;
> >> -
> >> -static unsigned int exynos4210_volt_table[] = {
> >> -     1250000, 1150000, 1050000, 975000, 950000,
> >> -};
> >> -
> >> -static struct cpufreq_frequency_table exynos4210_freq_table[] = {
> >> -     {L0, 1200 * 1000},
> >> -     {L1, 1000 * 1000},
> >> -     {L2,  800 * 1000},
> >> -     {L3,  500 * 1000},
> >> -     {L4,  200 * 1000},
> >> -     {0, CPUFREQ_TABLE_END},
> >> -};
> >> -
> >> -static struct apll_freq apll_freq_4210[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> PCLK_DBG, APLL, RESERVED
> >> -      * clock divider for COPY, HPM, RESERVED
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
> >> -     APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
> >> -     APLL_FREQ(800,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
> >> -     APLL_FREQ(500,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
> >> -     APLL_FREQ(200,  0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
> >> -};
> >> -
> >> -static void exynos4210_set_clkdiv(unsigned int div_index)
> >> -{
> >> -     unsigned int tmp;
> >> -
> >> -     /* Change Divider - CPU0 */
> >> -
> >> -     tmp = apll_freq_4210[div_index].clk_div_cpu0;
> >> -
> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
> >> -
> >> -     do {
> >> -             tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
> >> -     } while (tmp & 0x1111111);
> >> -
> >> -     /* Change Divider - CPU1 */
> >> -
> >> -     tmp = apll_freq_4210[div_index].clk_div_cpu1;
> >> -
> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
> >> -
> >> -     do {
> >> -             tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
> >> -     } while (tmp & 0x11);
> >> -}
> >> -
> >> -static void exynos4210_set_apll(unsigned int index)
> >> -{
> >> -     unsigned int tmp, freq = apll_freq_4210[index].freq;
> >> -
> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> -     clk_set_parent(moutcore, mout_mpll);
> >> -
> >> -     do {
> >> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
> >> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
> >> -             tmp &= 0x7;
> >> -     } while (tmp != 0x2);
> >> -
> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> -
> >> -     /* MUX_CORE_SEL = APLL */
> >> -     clk_set_parent(moutcore, mout_apll);
> >> -
> >> -     do {
> >> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
> >> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
> >> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
> >> -}
> >> -
> >> -static void exynos4210_set_frequency(unsigned int old_index,
> >> -                                  unsigned int new_index)
> >> -{
> >> -     if (old_index > new_index) {
> >> -             exynos4210_set_clkdiv(new_index);
> >> -             exynos4210_set_apll(new_index);
> >> -     } else if (old_index < new_index) {
> >> -             exynos4210_set_apll(new_index);
> >> -             exynos4210_set_clkdiv(new_index);
> >> -     }
> >> -}
> >> -
> >> -int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
> >> -{
> >> -     unsigned long rate;
> >> -
> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> -     if (IS_ERR(cpu_clk))
> >> -             return PTR_ERR(cpu_clk);
> >> -
> >> -     moutcore = clk_get(NULL, "moutcore");
> >> -     if (IS_ERR(moutcore))
> >> -             goto err_moutcore;
> >> -
> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> -     if (IS_ERR(mout_mpll))
> >> -             goto err_mout_mpll;
> >> -
> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> -
> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> -     if (IS_ERR(mout_apll))
> >> -             goto err_mout_apll;
> >> -
> >> -     info->mpll_freq_khz = rate;
> >> -     /* 800Mhz */
> >> -     info->pll_safe_idx = L2;
> >> -     info->cpu_clk = cpu_clk;
> >> -     info->volt_table = exynos4210_volt_table;
> >> -     info->freq_table = exynos4210_freq_table;
> >> -     info->set_freq = exynos4210_set_frequency;
> >> -
> >> -     return 0;
> >> -
> >> -err_mout_apll:
> >> -     clk_put(mout_mpll);
> >> -err_mout_mpll:
> >> -     clk_put(moutcore);
> >> -err_moutcore:
> >> -     clk_put(cpu_clk);
> >> -
> >> -     pr_debug("%s: failed initialization\n", __func__);
> >> -     return -EINVAL;
> >> -}
> >> diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c
> >> b/drivers/cpufreq/exynos4x12-cpufreq.c deleted file mode 100644
> >> index 7c11ace..0000000
> >> --- a/drivers/cpufreq/exynos4x12-cpufreq.c
> >> +++ /dev/null
> >> @@ -1,211 +0,0 @@
> >> -/*
> >> - * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
> >> - *           http://www.samsung.com
> >> - *
> >> - * EXYNOS4X12 - CPU frequency scaling 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.
> >> -*/
> >> -
> >> -#include <linux/module.h>
> >> -#include <linux/kernel.h>
> >> -#include <linux/err.h>
> >> -#include <linux/clk.h>
> >> -#include <linux/io.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/cpufreq.h>
> >> -
> >> -#include "exynos-cpufreq.h"
> >> -
> >> -static struct clk *cpu_clk;
> >> -static struct clk *moutcore;
> >> -static struct clk *mout_mpll;
> >> -static struct clk *mout_apll;
> >> -
> >> -static unsigned int exynos4x12_volt_table[] = {
> >> -     1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
> >> 1037500,
> >> -     1000000,  987500,  975000,  950000,  925000,  900000,  900000
> >> -};
> >> -
> >> -static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
> >> -     {CPUFREQ_BOOST_FREQ, 1500 * 1000},
> >
> > Here, you are removing BOOST support for Exynos4412, without any
> > code, which brings back this functionality in the new code.
> 
> Sorry, I did not notice this new feature in here.
> 
> >
> > I'd propose adding new property to cpus node and during
> > operating-points parsing mark the entry at the
> > cpufreq_frequency_table accordingly.
> 
> Okay, would you be adding support for this or do you want me to do
> this?

I think, that BOOST support shall be preserved in the clean up patches.
Otherwise your work introduce regression.

Please add support for boost in the next version of this patch series.

> 
> Thanks,
> Thomas.
> 
> >
> >> -     {L1, 1400 * 1000},
> >> -     {L2, 1300 * 1000},
> >> -     {L3, 1200 * 1000},
> >> -     {L4, 1100 * 1000},
> >> -     {L5, 1000 * 1000},
> >> -     {L6,  900 * 1000},
> >> -     {L7,  800 * 1000},
> >> -     {L8,  700 * 1000},
> >> -     {L9,  600 * 1000},
> >> -     {L10, 500 * 1000},
> >> -     {L11, 400 * 1000},
> >> -     {L12, 300 * 1000},
> >> -     {L13, 200 * 1000},
> >> -     {0, CPUFREQ_TABLE_END},
> >> -};
> >> -
> >> -static struct apll_freq *apll_freq_4x12;
> >> -
> >> -static struct apll_freq apll_freq_4212[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> PCLK_DBG, APLL, CORE2
> >> -      * clock divider for COPY, HPM, RESERVED
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
> >> -};
> >> -
> >> -static struct apll_freq apll_freq_4412[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> PCLK_DBG, APLL, CORE2
> >> -      * clock divider for COPY, HPM, CORES
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
> >> -};
> >> -
> >> -static void exynos4x12_set_clkdiv(unsigned int div_index)
> >> -{
> >> -     unsigned int tmp;
> >> -     unsigned int stat_cpu1;
> >> -
> >> -     /* Change Divider - CPU0 */
> >> -
> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu0;
> >> -
> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
> >> -
> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
> >> -             cpu_relax();
> >> -
> >> -     /* Change Divider - CPU1 */
> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu1;
> >> -
> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
> >> -     if (soc_is_exynos4212())
> >> -             stat_cpu1 = 0x11;
> >> -     else
> >> -             stat_cpu1 = 0x111;
> >> -
> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
> >> -             cpu_relax();
> >> -}
> >> -
> >> -static void exynos4x12_set_apll(unsigned int index)
> >> -{
> >> -     unsigned int tmp, freq = apll_freq_4x12[index].freq;
> >> -
> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> -     clk_set_parent(moutcore, mout_mpll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
> >> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
> >> -             tmp &= 0x7;
> >> -     } while (tmp != 0x2);
> >> -
> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> -
> >> -     /* MUX_CORE_SEL = APLL */
> >> -     clk_set_parent(moutcore, mout_apll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
> >> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
> >> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
> >> -}
> >> -
> >> -static void exynos4x12_set_frequency(unsigned int old_index,
> >> -                               unsigned int new_index)
> >> -{
> >> -     if (old_index > new_index) {
> >> -             exynos4x12_set_clkdiv(new_index);
> >> -             exynos4x12_set_apll(new_index);
> >> -     } else if (old_index < new_index) {
> >> -             exynos4x12_set_apll(new_index);
> >> -             exynos4x12_set_clkdiv(new_index);
> >> -     }
> >> -}
> >> -
> >> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
> >> -{
> >> -     unsigned long rate;
> >> -
> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> -     if (IS_ERR(cpu_clk))
> >> -             return PTR_ERR(cpu_clk);
> >> -
> >> -     moutcore = clk_get(NULL, "moutcore");
> >> -     if (IS_ERR(moutcore))
> >> -             goto err_moutcore;
> >> -
> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> -     if (IS_ERR(mout_mpll))
> >> -             goto err_mout_mpll;
> >> -
> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> -
> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> -     if (IS_ERR(mout_apll))
> >> -             goto err_mout_apll;
> >> -
> >> -     if (soc_is_exynos4212())
> >> -             apll_freq_4x12 = apll_freq_4212;
> >> -     else
> >> -             apll_freq_4x12 = apll_freq_4412;
> >> -
> >> -     info->mpll_freq_khz = rate;
> >> -     /* 800Mhz */
> >> -     info->pll_safe_idx = L7;
> >> -     info->cpu_clk = cpu_clk;
> >> -     info->volt_table = exynos4x12_volt_table;
> >> -     info->freq_table = exynos4x12_freq_table;
> >> -     info->set_freq = exynos4x12_set_frequency;
> >> -
> >> -     return 0;
> >> -
> >> -err_mout_apll:
> >> -     clk_put(mout_mpll);
> >> -err_mout_mpll:
> >> -     clk_put(moutcore);
> >> -err_moutcore:
> >> -     clk_put(cpu_clk);
> >> -
> >> -     pr_debug("%s: failed initialization\n", __func__);
> >> -     return -EINVAL;
> >> -}
> >> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
> >> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
> >> index 5f90b82..0000000
> >> --- a/drivers/cpufreq/exynos5250-cpufreq.c
> >> +++ /dev/null
> >> @@ -1,183 +0,0 @@
> >> -/*
> >> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
> >> - *           http://www.samsung.com
> >> - *
> >> - * EXYNOS5250 - CPU frequency scaling 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.
> >> -*/
> >> -
> >> -#include <linux/module.h>
> >> -#include <linux/kernel.h>
> >> -#include <linux/err.h>
> >> -#include <linux/clk.h>
> >> -#include <linux/io.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/cpufreq.h>
> >> -
> >> -#include <mach/map.h>
> >> -
> >> -#include "exynos-cpufreq.h"
> >> -
> >> -static struct clk *cpu_clk;
> >> -static struct clk *moutcore;
> >> -static struct clk *mout_mpll;
> >> -static struct clk *mout_apll;
> >> -
> >> -static unsigned int exynos5250_volt_table[] = {
> >> -     1300000, 1250000, 1225000, 1200000, 1150000,
> >> -     1125000, 1100000, 1075000, 1050000, 1025000,
> >> -     1012500, 1000000,  975000,  950000,  937500,
> >> -     925000
> >> -};
> >> -
> >> -static struct cpufreq_frequency_table exynos5250_freq_table[] = {
> >> -     {L0, 1700 * 1000},
> >> -     {L1, 1600 * 1000},
> >> -     {L2, 1500 * 1000},
> >> -     {L3, 1400 * 1000},
> >> -     {L4, 1300 * 1000},
> >> -     {L5, 1200 * 1000},
> >> -     {L6, 1100 * 1000},
> >> -     {L7, 1000 * 1000},
> >> -     {L8,  900 * 1000},
> >> -     {L9,  800 * 1000},
> >> -     {L10, 700 * 1000},
> >> -     {L11, 600 * 1000},
> >> -     {L12, 500 * 1000},
> >> -     {L13, 400 * 1000},
> >> -     {L14, 300 * 1000},
> >> -     {L15, 200 * 1000},
> >> -     {0, CPUFREQ_TABLE_END},
> >> -};
> >> -
> >> -static struct apll_freq apll_freq_5250[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG,
> >> APLL, ARM2
> >> -      * clock divider for COPY, HPM, RESERVED
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
> >> -     APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
> >> -     APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
> >> -     APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
> >> -     APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
> >> -     APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
> >> -     APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
> >> -     APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
> >> -     APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
> >> -     APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
> >> -     APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
> >> -     APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
> >> -     APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
> >> -     APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
> >> -     APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
> >> -     APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
> >> -};
> >> -
> >> -static void set_clkdiv(unsigned int div_index)
> >> -{
> >> -     unsigned int tmp;
> >> -
> >> -     /* Change Divider - CPU0 */
> >> -
> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu0;
> >> -
> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
> >> -
> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
> >> -             cpu_relax();
> >> -
> >> -     /* Change Divider - CPU1 */
> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu1;
> >> -
> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
> >> -
> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
> >> -             cpu_relax();
> >> -}
> >> -
> >> -static void set_apll(unsigned int index)
> >> -{
> >> -     unsigned int tmp;
> >> -     unsigned int freq = apll_freq_5250[index].freq;
> >> -
> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> -     clk_set_parent(moutcore, mout_mpll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
> >> -             tmp &= 0x7;
> >> -     } while (tmp != 0x2);
> >> -
> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> -
> >> -     /* MUX_CORE_SEL = APLL */
> >> -     clk_set_parent(moutcore, mout_apll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
> >> -             tmp &= (0x7 << 16);
> >> -     } while (tmp != (0x1 << 16));
> >> -}
> >> -
> >> -static void exynos5250_set_frequency(unsigned int old_index,
> >> -                               unsigned int new_index)
> >> -{
> >> -     if (old_index > new_index) {
> >> -             set_clkdiv(new_index);
> >> -             set_apll(new_index);
> >> -     } else if (old_index < new_index) {
> >> -             set_apll(new_index);
> >> -             set_clkdiv(new_index);
> >> -     }
> >> -}
> >> -
> >> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
> >> -{
> >> -     unsigned long rate;
> >> -
> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> -     if (IS_ERR(cpu_clk))
> >> -             return PTR_ERR(cpu_clk);
> >> -
> >> -     moutcore = clk_get(NULL, "mout_cpu");
> >> -     if (IS_ERR(moutcore))
> >> -             goto err_moutcore;
> >> -
> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> -     if (IS_ERR(mout_mpll))
> >> -             goto err_mout_mpll;
> >> -
> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> -
> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> -     if (IS_ERR(mout_apll))
> >> -             goto err_mout_apll;
> >> -
> >> -     info->mpll_freq_khz = rate;
> >> -     /* 800Mhz */
> >> -     info->pll_safe_idx = L9;
> >> -     info->cpu_clk = cpu_clk;
> >> -     info->volt_table = exynos5250_volt_table;
> >> -     info->freq_table = exynos5250_freq_table;
> >> -     info->set_freq = exynos5250_set_frequency;
> >> -
> >> -     return 0;
> >> -
> >> -err_mout_apll:
> >> -     clk_put(mout_mpll);
> >> -err_mout_mpll:
> >> -     clk_put(moutcore);
> >> -err_moutcore:
> >> -     clk_put(cpu_clk);
> >> -
> >> -     pr_err("%s: failed initialization\n", __func__);
> >> -     return -EINVAL;
> >> -}
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-01-20  8:24   ` Lukasz Majewski
@ 2014-01-21  8:35     ` Thomas Abraham
  2014-01-21 10:25       ` Lukasz Majewski
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Mon, Jan 20, 2014 at 1:54 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> The CPU clock provider supplies the clock to the CPU clock domain. The
>> composition and organization of the CPU clock provider could vary
>> among Exynos SoCs. A CPU clock provider can be composed of clock mux,
>> dividers and gates. This patch defines a new clock type for CPU clock
>> provider and adds infrastructure to register the CPU clock providers
>> for Samsung platforms.
>>
>> In addition to this, the arm cpu clock provider for Exynos4210 and
>> compatible SoCs is instantiated using the new cpu clock type. The
>> clock frequency table and the clock configuration data for this clock
>> is obtained from device tree. This implementation is reusable for
>> Exynos4x12 and Exynos5250 SoCs as well.
>>
>> Cc: Tomasz Figa <t.figa@samsung.com>
>> Cc: Lukasz Majewski <l.majewski@majess.pl>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  drivers/clk/samsung/Makefile  |    2 +-
>>  drivers/clk/samsung/clk-cpu.c |  345
>> +++++++++++++++++++++++++++++++++++++++++
>> drivers/clk/samsung/clk.h     |    3 + 3 files changed, 349
>> insertions(+), 1 deletions(-) create mode 100644
>> drivers/clk/samsung/clk-cpu.c
>>
>> diff --git a/drivers/clk/samsung/Makefile
>> b/drivers/clk/samsung/Makefile index 8eb4799..e2b453f 100644
>> --- a/drivers/clk/samsung/Makefile
>> +++ b/drivers/clk/samsung/Makefile
>> @@ -2,7 +2,7 @@
>>  # Samsung Clock specific Makefile
>>  #
>>
>> -obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o
>> +obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o clk-cpu.o
>>  obj-$(CONFIG_ARCH_EXYNOS4)   += clk-exynos4.o
>>  obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
>>  obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
>> diff --git a/drivers/clk/samsung/clk-cpu.c
>> b/drivers/clk/samsung/clk-cpu.c new file mode 100644
>> index 0000000..92fba45
>> --- /dev/null
>> +++ b/drivers/clk/samsung/clk-cpu.c
>> @@ -0,0 +1,345 @@
>> +/*
>> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
>> + * Author: Thomas Abraham <thomas.ab@samsung.com>
>> + *
>> + * 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 contains the utility functions to register the cpu
>> clocks
>> + * for samsung platforms.
>> +*/
>> +
>> +#include <linux/errno.h>
>> +#include "clk.h"
>> +
>> +#define SRC_CPU                      0x0
>> +#define STAT_CPU             0x200
>> +#define DIV_CPU0             0x300
>> +#define DIV_CPU1             0x304
>> +#define DIV_STAT_CPU0                0x400
>> +#define DIV_STAT_CPU1                0x404
>> +
>> +/**
>> + * struct samsung_cpuclk_freq_table: table of frequency supported by
>> + * a cpu clock and associated data if any.
>> + * @freq: points to a table of supported frequencies (in KHz)
>> + * @freq_count: number of entries in the frequency table
>> + * @data: cpu clock specific data, if any
>> + *
>> + * This structure holds the frequency options supported by the cpu
>> clock in
>> + * which this structure is contained. The data pointer is an
>> optional data
>> + * that can provide any additional configuration options for the
>> supported
>> + * frequencies. This structure is intended to be reusable for all
>> cpu clocks
>> + * in Samsung SoC based platforms
>> + */
>> +struct samsung_cpuclk_freq_table {
>> +     const unsigned long     *freq;       /* in KHz */
>> +     unsigned long           freq_count;
>> +     const void              *data;
>> +};
>> +
>> +/**
>> + * struct exynos4210_freq_data: format of auxillary data associated
>> with
>> + * each frequency supported by the cpu clock for exynos4210.
>> + * @parent_freq: The frequency of the parent clock required to
>> generate the
>> + * supported cpu clock speed.
>> + * @div0: value to be programmed in the div_cpu0 register.
>> + * @div1: value to be programmed in the div_cpu1 register.
>> + *
>> + * This structure holds the auxillary configuration data for each
>> supported
>> + * cpu clock frequency on Exynos4210 and compatible SoCs.
>> + */
>> +struct exynos4210_freq_data {
>> +     unsigned long   parent_freq;
>> +     unsigned int    div0;
>> +     unsigned int    div1;
>> +};
>> +
>> +/**
>> + * struct samsung_cpuclk: information about clock supplied to a CPU
>> core.
>> + * @hw: handle between ccf and cpu clock.
>> + * @ctrl_base: base address of the clock controller.
>> + * @offset: offset from the ctrl_base address where the cpu clock
>> div/mux
>> + *          registers can be accessed.
>> + * @parent: clock handle representing the clock output of the parent
>> clock.
>> + * @freq_table: the frequency table supported by this cpu clock.
>> + */
>> +struct samsung_cpuclk {
>> +     struct clk_hw           hw;
>> +     void __iomem            *ctrl_base;
>> +     unsigned long           offset;
>> +     struct clk              *parent;
>> +     const struct samsung_cpuclk_freq_table *freq_table;
>> +};
>> +
>> +#define to_samsung_cpuclk(hw)        container_of(hw, struct
>> samsung_cpuclk, hw) +
>> +/**
>> + * struct samsung_cpuclk_match_data: soc specific data for cpu
>> clocks.
>> + * @parser: pointer to a function that can parse SoC specific cpu
>> clock
>> + *   frequency and associated configuration data.
>> + * @offset: optional offset from base of clock controller register
>> base,
>> + *   to be used when accessing clock controller registers
>> related to the
>> + * cpu clock.
>> + * @offset: offset from the ctrl_base address where the cpu clock
>> div/mux
>> + *   registers can be accessed.
>> + */
>> +struct samsung_cpuclk_match_data {
>> +     int (*parser)(struct device_node *,
>> +                     struct samsung_cpuclk_freq_table **);
>> +     unsigned int offset;
>> +};
>> +
>> +/* This is a helper function to perform clock rounding for cpu
>> clocks. */ +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
>> +                     unsigned long drate, unsigned long *prate)
>> +{
>> +     struct samsung_cpuclk *cpuclk = to_samsung_cpuclk(hw);
>> +     const struct samsung_cpuclk_freq_table *freq_tbl;
>> +     int i;
>> +
>> +     freq_tbl = cpuclk->freq_table;
>> +     drate /= 1000;
>> +
>> +     for (i = 0; i < freq_tbl->freq_count; i++) {
>> +             if (drate >= freq_tbl->freq[i])
>> +                     return freq_tbl->freq[i] * 1000;
>> +     }
>> +     return freq_tbl->freq[i - 1] * 1000;
>> +}
>> +
>> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) +
>> 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >>
>> 28) & 0xf) + 1) +
>> +/*
>> + * CPU clock speed for Exynos4210 and compatible SoCs is
>> + * parent clock speed / core1_ratio / core2_ratio
>> + */
>> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
>> +                             unsigned long parent_rate)
>> +{
>> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
>> +     void __iomem *base = armclk->ctrl_base + armclk->offset;
>> +
>> +     return parent_rate / EXYNOS4210_ARM_DIV1(base) /
>> +                             EXYNOS4210_ARM_DIV2(base);
>> +}
>> +
>> +/* set rate callback for cpuclk type on Exynos4210 and similar SoCs
>> */ +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned
>> long drate,
>> +                                     unsigned long prate)
>> +{
>> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
>> +     const struct samsung_cpuclk_freq_table *freq_tbl;
>> +     const struct exynos4210_freq_data *freq_data;
>> +     unsigned long mux_reg, idx;
>> +     void __iomem *base;
>> +
>> +     if (drate == prate)
>> +             return 0;
>> +
>> +     freq_tbl = armclk->freq_table;
>> +     freq_data = freq_tbl->data;
>> +     base = armclk->ctrl_base + armclk->offset;
>> +
>> +     for (idx = 0; idx < freq_tbl->freq_count; idx++, freq_data++)
>> +             if ((freq_tbl->freq[idx] * 1000) == drate)
>> +                     break;
>> +
>> +     if (drate < prate) {
>> +             mux_reg = readl(base + SRC_CPU);
>> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
>> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
>> +                     ;
>> +
>> +             clk_set_rate(armclk->parent, drate);
>> +     }
>> +
>> +     writel(freq_data->div0, base + DIV_CPU0);
>> +     while (readl(base + DIV_STAT_CPU0) != 0)
>> +             ;
>> +     writel(freq_data->div1, base + DIV_CPU1);
>> +     while (readl(base + DIV_STAT_CPU1) != 0)
>> +             ;
>> +
>> +     if (drate > prate) {
>> +             mux_reg = readl(base + SRC_CPU);
>> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
>> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
>> +                     ;
>> +
>> +             clk_set_rate(armclk->parent, freq_data->parent_freq
>> * 1000);
>> +     }
>> +
>> +     mux_reg = readl(base + SRC_CPU);
>> +     writel(mux_reg & ~(1 << 16), base + SRC_CPU);
>> +     while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
>> +                     ;
>> +     return 0;
>> +}
>> +
>> +/* clock ops for armclk on Exynos4210 and compatible platforms. */
>> +static const struct clk_ops exynos4210_armclk_clk_ops = {
>> +     .recalc_rate = exynos4210_armclk_recalc_rate,
>> +     .round_rate = samsung_cpuclk_round_rate,
>> +     .set_rate = exynos4210_armclk_set_rate,
>> +};
>> +
>> +/* helper function to register a cpu clock */
>> +static void __init samsung_cpuclk_register(unsigned int lookup_id,
>> +             const char *name, const char *parent, const struct
>> clk_ops *ops,
>> +             const struct samsung_cpuclk_freq_table *freq_tbl,
>> +             void __iomem *reg_base,
>> +             const struct samsung_cpuclk_match_data *data)
>> +{
>> +     struct samsung_cpuclk *cpuclk;
>> +     struct clk_init_data init;
>> +     struct clk *clk;
>> +
>> +     cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
>> +     if (!cpuclk) {
>> +             pr_err("%s: could not allocate memory for cpuclk
>> %s\n",
>> +                                     __func__, name);
>> +             return;
>> +     }
>> +
>> +     init.name = name;
>> +     init.flags = CLK_GET_RATE_NOCACHE;
>> +     init.parent_names = &parent;
>> +     init.num_parents = 1;
>> +     init.ops = ops;
>> +
>> +     cpuclk->hw.init = &init;
>> +     cpuclk->ctrl_base = reg_base;
>> +     cpuclk->offset = data->offset;
>> +     cpuclk->freq_table = freq_tbl;
>> +     cpuclk->parent = __clk_lookup(parent);
>> +
>> +     clk = clk_register(NULL, &cpuclk->hw);
>> +     if (IS_ERR(clk)) {
>> +             pr_err("%s: could not register cpuclk %s\n",
>> __func__,     name);
>> +             kfree(cpuclk);
>> +             return;
>> +     }
>> +     samsung_clk_add_lookup(clk, lookup_id);
>> +}
>> +
>> +#define EXYNOS4210_DIV_CPU01(d0, d1, d2, d3, d4, d5, d6,
>> d7)           \
>> +             ((d0 << 28) | (d1 << 24) | (d2 << 20) | (d3
>> << 16) |      \
>> +              (d4 << 12) | (d5 << 8) | (d6 << 4) | (d7 << 0))
>> +#define EXYNOS4210_DIV_CPU11(d0, d1,
>> d2)                           \
>> +             ((d0 << 8) | (d1 << 4) | (d2 << 0))
>> +#define EXYNOS4210_CFG_LEN 13
>> +
>> +/*
>> + * parse cpu clock frequency table and auxillary configuration data
>> from dt
>> + * for exynos4210 and compatible SoC's.
>> + */
>> +static int exynos4210_armclk_cfg_parser(struct device_node *np,
>> +             struct samsung_cpuclk_freq_table **tbl)
>> +{
>> +     struct samsung_cpuclk_freq_table *freq_tbl;
>> +     struct exynos4210_freq_data *fdata, *t_fdata;
>> +     unsigned long *freqs, cfg[EXYNOS4210_CFG_LEN];
>> +     const struct property *prop;
>> +     unsigned int tbl_sz, i, j;
>> +     const __be32 *val;
>> +     int ret;
>> +
>> +     prop = of_find_property(np, "arm-frequency-table", NULL);
>> +     if (!prop)
>> +             return -EINVAL;
>> +     if (!prop->value)
>> +             return -EINVAL;
>> +     if ((prop->length / sizeof(u32)) % EXYNOS4210_CFG_LEN)
>
> Cannot we have the EXYNOS4210_CFG_LEN parsed from DT as well?

As per Rob's suggestion, the clock divider ration table will be
removed. So this portion of the code will be reworked.

>
>> +             return -EINVAL;
>> +     tbl_sz = (prop->length / sizeof(u32)) / EXYNOS4210_CFG_LEN;
>> +
>> +     freq_tbl = kzalloc(sizeof(*freq_tbl), GFP_KERNEL);
>> +     if (!freq_tbl)
>> +             return -ENOMEM;
>> +
>> +     freqs = kzalloc(sizeof(u32) * tbl_sz, GFP_KERNEL);
>> +     if (!freqs) {
>> +             ret = -ENOMEM;
>> +             goto free_freq_tbl;
>> +     }
>> +
>> +     fdata = kzalloc(sizeof(*fdata) * tbl_sz, GFP_KERNEL);
>> +     if (!fdata) {
>> +             ret = -ENOMEM;
>> +             goto free_freqs;
>> +     }
>> +     t_fdata = fdata;
>> +
>> +     val = prop->value;
>> +     for (i = 0; i < tbl_sz; i++, fdata++) {
>> +             for (j = 0; j < EXYNOS4210_CFG_LEN; j++)
>> +                     cfg[j] = be32_to_cpup(val++);
>> +             freqs[i] = cfg[0];
>> +             fdata->parent_freq = cfg[1];
>
> Why do we need the separate parent_freq entry here?
>
> In the patch 4/7 the freqs (cfg[0]) and parent_freq (cfg[1]) values are
> the same for all supported devices (at "arm-frequency-table").
>
> What is the rationale for having those values duplicated in the DT?

The intention was to support frequencies which may not be direct
output of the parent PLL clock. For instance, if the PLL supports
200MHz, 400MHz and 600MHz and the CPU clock needs to be set to 300MHz,
then 600MHz / 2 is a valid clock output for the cpu clock. So this is
an example where the cpu clock speed is different from its parent
clock speed.

If possible, I will try and remove the need for this table in the next version.

Thanks,
Thomas.

>
>
>> +             fdata->div0 = EXYNOS4210_DIV_CPU01(cfg[9], cfg[8],
>> cfg[7],
>> +                             cfg[6], cfg[5], cfg[4], cfg[3],
>> cfg[2]);
>> +             fdata->div1 = EXYNOS4210_DIV_CPU11(cfg[12], cfg[11],
>> cfg[10]);
>> +     }
>> +
>> +     freq_tbl->freq = freqs;
>> +     freq_tbl->freq_count = tbl_sz;
>> +     freq_tbl->data = t_fdata;
>> +     *tbl = freq_tbl;
>> +     return 0;
>> +
>> +free_freqs:
>> +     kfree(freqs);
>> +free_freq_tbl:
>> +     kfree(freq_tbl);
>> +     return ret;
>> +}
>> +
>> +static struct samsung_cpuclk_match_data exynos4210_cpuclk_match_data
>> = {
>> +     .parser = exynos4210_armclk_cfg_parser,
>> +     .offset = 0x14200,
>> +};
>> +
>> +static struct samsung_cpuclk_match_data exynos5250_cpuclk_match_data
>> = {
>> +     .parser = exynos4210_armclk_cfg_parser,
>> +     .offset = 0x200,
>> +};
>> +
>> +static const struct of_device_id samsung_clock_ids[] = {
>> +     { .compatible = "samsung,exynos4210-clock",
>> +                     .data = &exynos4210_cpuclk_match_data, },
>> +     { .compatible = "samsung,exynos4412-clock",
>> +                     .data = &exynos4210_cpuclk_match_data, },
>> +     { .compatible = "samsung,exynos5250-clock",
>> +                     .data = &exynos5250_cpuclk_match_data, },
>> +};
>> +
>> +int __init samsung_register_arm_clock(struct device_node *np,
>> +             unsigned int lookup_id, const char *parent,
>> void __iomem *base) +{
>> +     const struct of_device_id *match;
>> +     struct samsung_cpuclk_freq_table *freq_table;
>> +     const struct samsung_cpuclk_match_data *data;
>> +     int ret;
>> +
>> +     match = of_match_node(samsung_clock_ids, np);
>> +     if (!match) {
>> +             pr_err("%s: could not determine soc type\n",
>> __func__);
>> +             return -EINVAL;
>> +     }
>> +
>> +     data = match->data;
>> +     ret = data->parser(np, &freq_table);
>> +     if (ret) {
>> +             pr_err("%s: error %d in parsing arm clock freq
>> table",
>> +                                             __func__, ret);
>> +             return -EINVAL;
>> +     }
>> +
>> +     samsung_cpuclk_register(lookup_id, "armclk", parent,
>> +             &exynos4210_armclk_clk_ops, freq_table, base, data);
>> +
>> +     return 0;
>> +}
>> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
>> index 31b4174..a759330 100644
>> --- a/drivers/clk/samsung/clk.h
>> +++ b/drivers/clk/samsung/clk.h
>> @@ -340,4 +340,7 @@ extern void __init
>> samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
>>  extern unsigned long _get_rate(const char *clk_name);
>>
>> +extern int __init samsung_register_arm_clock(struct device_node *np,
>> +             unsigned int lookup_id, const char *parent, void
>> __iomem *base); +
>>  #endif /* __SAMSUNG_CLK_H */
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-01-21  8:35     ` Thomas Abraham
@ 2014-01-21 10:25       ` Lukasz Majewski
  2014-01-21 10:38         ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-21 10:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> Hi Lukasz,
> 
> On Mon, Jan 20, 2014 at 1:54 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> The CPU clock provider supplies the clock to the CPU clock domain.
> >> The composition and organization of the CPU clock provider could
> >> vary among Exynos SoCs. A CPU clock provider can be composed of
> >> clock mux, dividers and gates. This patch defines a new clock type
> >> for CPU clock provider and adds infrastructure to register the CPU
> >> clock providers for Samsung platforms.
> >>
> >> In addition to this, the arm cpu clock provider for Exynos4210 and
> >> compatible SoCs is instantiated using the new cpu clock type. The
> >> clock frequency table and the clock configuration data for this
> >> clock is obtained from device tree. This implementation is
> >> reusable for Exynos4x12 and Exynos5250 SoCs as well.
> >>
> >> Cc: Tomasz Figa <t.figa@samsung.com>
> >> Cc: Lukasz Majewski <l.majewski@majess.pl>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> ---
> >>  drivers/clk/samsung/Makefile  |    2 +-
> >>  drivers/clk/samsung/clk-cpu.c |  345
> >> +++++++++++++++++++++++++++++++++++++++++
> >> drivers/clk/samsung/clk.h     |    3 + 3 files changed, 349
> >> insertions(+), 1 deletions(-) create mode 100644
> >> drivers/clk/samsung/clk-cpu.c
> >>
> >> diff --git a/drivers/clk/samsung/Makefile
> >> b/drivers/clk/samsung/Makefile index 8eb4799..e2b453f 100644
> >> --- a/drivers/clk/samsung/Makefile
> >> +++ b/drivers/clk/samsung/Makefile
> >> @@ -2,7 +2,7 @@
> >>  # Samsung Clock specific Makefile
> >>  #
> >>
> >> -obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o
> >> +obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o clk-cpu.o
> >>  obj-$(CONFIG_ARCH_EXYNOS4)   += clk-exynos4.o
> >>  obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
> >>  obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
> >> diff --git a/drivers/clk/samsung/clk-cpu.c
> >> b/drivers/clk/samsung/clk-cpu.c new file mode 100644
> >> index 0000000..92fba45
> >> --- /dev/null
> >> +++ b/drivers/clk/samsung/clk-cpu.c
> >> @@ -0,0 +1,345 @@
> >> +/*
> >> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> >> + * Author: Thomas Abraham <thomas.ab@samsung.com>
> >> + *
> >> + * 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 contains the utility functions to register the cpu
> >> clocks
> >> + * for samsung platforms.
> >> +*/
> >> +
> >> +#include <linux/errno.h>
> >> +#include "clk.h"
> >> +
> >> +#define SRC_CPU                      0x0
> >> +#define STAT_CPU             0x200
> >> +#define DIV_CPU0             0x300
> >> +#define DIV_CPU1             0x304
> >> +#define DIV_STAT_CPU0                0x400
> >> +#define DIV_STAT_CPU1                0x404
> >> +
> >> +/**
> >> + * struct samsung_cpuclk_freq_table: table of frequency supported
> >> by
> >> + * a cpu clock and associated data if any.
> >> + * @freq: points to a table of supported frequencies (in KHz)
> >> + * @freq_count: number of entries in the frequency table
> >> + * @data: cpu clock specific data, if any
> >> + *
> >> + * This structure holds the frequency options supported by the cpu
> >> clock in
> >> + * which this structure is contained. The data pointer is an
> >> optional data
> >> + * that can provide any additional configuration options for the
> >> supported
> >> + * frequencies. This structure is intended to be reusable for all
> >> cpu clocks
> >> + * in Samsung SoC based platforms
> >> + */
> >> +struct samsung_cpuclk_freq_table {
> >> +     const unsigned long     *freq;       /* in KHz */
> >> +     unsigned long           freq_count;
> >> +     const void              *data;
> >> +};
> >> +
> >> +/**
> >> + * struct exynos4210_freq_data: format of auxillary data
> >> associated with
> >> + * each frequency supported by the cpu clock for exynos4210.
> >> + * @parent_freq: The frequency of the parent clock required to
> >> generate the
> >> + * supported cpu clock speed.
> >> + * @div0: value to be programmed in the div_cpu0 register.
> >> + * @div1: value to be programmed in the div_cpu1 register.
> >> + *
> >> + * This structure holds the auxillary configuration data for each
> >> supported
> >> + * cpu clock frequency on Exynos4210 and compatible SoCs.
> >> + */
> >> +struct exynos4210_freq_data {
> >> +     unsigned long   parent_freq;
> >> +     unsigned int    div0;
> >> +     unsigned int    div1;
> >> +};
> >> +
> >> +/**
> >> + * struct samsung_cpuclk: information about clock supplied to a
> >> CPU core.
> >> + * @hw: handle between ccf and cpu clock.
> >> + * @ctrl_base: base address of the clock controller.
> >> + * @offset: offset from the ctrl_base address where the cpu clock
> >> div/mux
> >> + *          registers can be accessed.
> >> + * @parent: clock handle representing the clock output of the
> >> parent clock.
> >> + * @freq_table: the frequency table supported by this cpu clock.
> >> + */
> >> +struct samsung_cpuclk {
> >> +     struct clk_hw           hw;
> >> +     void __iomem            *ctrl_base;
> >> +     unsigned long           offset;
> >> +     struct clk              *parent;
> >> +     const struct samsung_cpuclk_freq_table *freq_table;
> >> +};
> >> +
> >> +#define to_samsung_cpuclk(hw)        container_of(hw, struct
> >> samsung_cpuclk, hw) +
> >> +/**
> >> + * struct samsung_cpuclk_match_data: soc specific data for cpu
> >> clocks.
> >> + * @parser: pointer to a function that can parse SoC specific cpu
> >> clock
> >> + *   frequency and associated configuration data.
> >> + * @offset: optional offset from base of clock controller register
> >> base,
> >> + *   to be used when accessing clock controller registers
> >> related to the
> >> + * cpu clock.
> >> + * @offset: offset from the ctrl_base address where the cpu clock
> >> div/mux
> >> + *   registers can be accessed.
> >> + */
> >> +struct samsung_cpuclk_match_data {
> >> +     int (*parser)(struct device_node *,
> >> +                     struct samsung_cpuclk_freq_table **);
> >> +     unsigned int offset;
> >> +};
> >> +
> >> +/* This is a helper function to perform clock rounding for cpu
> >> clocks. */ +static long samsung_cpuclk_round_rate(struct clk_hw
> >> *hw,
> >> +                     unsigned long drate, unsigned long *prate)
> >> +{
> >> +     struct samsung_cpuclk *cpuclk = to_samsung_cpuclk(hw);
> >> +     const struct samsung_cpuclk_freq_table *freq_tbl;
> >> +     int i;
> >> +
> >> +     freq_tbl = cpuclk->freq_table;
> >> +     drate /= 1000;
> >> +
> >> +     for (i = 0; i < freq_tbl->freq_count; i++) {
> >> +             if (drate >= freq_tbl->freq[i])
> >> +                     return freq_tbl->freq[i] * 1000;
> >> +     }
> >> +     return freq_tbl->freq[i - 1] * 1000;
> >> +}
> >> +
> >> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf)
> >> + 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0)
> >> >> 28) & 0xf) + 1) +
> >> +/*
> >> + * CPU clock speed for Exynos4210 and compatible SoCs is
> >> + * parent clock speed / core1_ratio / core2_ratio
> >> + */
> >> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw
> >> *hw,
> >> +                             unsigned long parent_rate)
> >> +{
> >> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
> >> +     void __iomem *base = armclk->ctrl_base + armclk->offset;
> >> +
> >> +     return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> >> +                             EXYNOS4210_ARM_DIV2(base);
> >> +}
> >> +
> >> +/* set rate callback for cpuclk type on Exynos4210 and similar
> >> SoCs */ +static int exynos4210_armclk_set_rate(struct clk_hw *hw,
> >> unsigned long drate,
> >> +                                     unsigned long prate)
> >> +{
> >> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
> >> +     const struct samsung_cpuclk_freq_table *freq_tbl;
> >> +     const struct exynos4210_freq_data *freq_data;
> >> +     unsigned long mux_reg, idx;
> >> +     void __iomem *base;
> >> +
> >> +     if (drate == prate)
> >> +             return 0;
> >> +
> >> +     freq_tbl = armclk->freq_table;
> >> +     freq_data = freq_tbl->data;
> >> +     base = armclk->ctrl_base + armclk->offset;
> >> +
> >> +     for (idx = 0; idx < freq_tbl->freq_count; idx++, freq_data++)
> >> +             if ((freq_tbl->freq[idx] * 1000) == drate)
> >> +                     break;
> >> +
> >> +     if (drate < prate) {
> >> +             mux_reg = readl(base + SRC_CPU);
> >> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
> >> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> >> +                     ;
> >> +
> >> +             clk_set_rate(armclk->parent, drate);
> >> +     }
> >> +
> >> +     writel(freq_data->div0, base + DIV_CPU0);
> >> +     while (readl(base + DIV_STAT_CPU0) != 0)
> >> +             ;
> >> +     writel(freq_data->div1, base + DIV_CPU1);
> >> +     while (readl(base + DIV_STAT_CPU1) != 0)
> >> +             ;
> >> +
> >> +     if (drate > prate) {
> >> +             mux_reg = readl(base + SRC_CPU);
> >> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
> >> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> >> +                     ;
> >> +
> >> +             clk_set_rate(armclk->parent, freq_data->parent_freq
> >> * 1000);
> >> +     }
> >> +
> >> +     mux_reg = readl(base + SRC_CPU);
> >> +     writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> >> +     while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> >> +                     ;
> >> +     return 0;
> >> +}
> >> +
> >> +/* clock ops for armclk on Exynos4210 and compatible platforms. */
> >> +static const struct clk_ops exynos4210_armclk_clk_ops = {
> >> +     .recalc_rate = exynos4210_armclk_recalc_rate,
> >> +     .round_rate = samsung_cpuclk_round_rate,
> >> +     .set_rate = exynos4210_armclk_set_rate,
> >> +};
> >> +
> >> +/* helper function to register a cpu clock */
> >> +static void __init samsung_cpuclk_register(unsigned int lookup_id,
> >> +             const char *name, const char *parent, const struct
> >> clk_ops *ops,
> >> +             const struct samsung_cpuclk_freq_table *freq_tbl,
> >> +             void __iomem *reg_base,
> >> +             const struct samsung_cpuclk_match_data *data)
> >> +{
> >> +     struct samsung_cpuclk *cpuclk;
> >> +     struct clk_init_data init;
> >> +     struct clk *clk;
> >> +
> >> +     cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> >> +     if (!cpuclk) {
> >> +             pr_err("%s: could not allocate memory for cpuclk
> >> %s\n",
> >> +                                     __func__, name);
> >> +             return;
> >> +     }
> >> +
> >> +     init.name = name;
> >> +     init.flags = CLK_GET_RATE_NOCACHE;
> >> +     init.parent_names = &parent;
> >> +     init.num_parents = 1;
> >> +     init.ops = ops;
> >> +
> >> +     cpuclk->hw.init = &init;
> >> +     cpuclk->ctrl_base = reg_base;
> >> +     cpuclk->offset = data->offset;
> >> +     cpuclk->freq_table = freq_tbl;
> >> +     cpuclk->parent = __clk_lookup(parent);
> >> +
> >> +     clk = clk_register(NULL, &cpuclk->hw);
> >> +     if (IS_ERR(clk)) {
> >> +             pr_err("%s: could not register cpuclk %s\n",
> >> __func__,     name);
> >> +             kfree(cpuclk);
> >> +             return;
> >> +     }
> >> +     samsung_clk_add_lookup(clk, lookup_id);
> >> +}
> >> +
> >> +#define EXYNOS4210_DIV_CPU01(d0, d1, d2, d3, d4, d5, d6,
> >> d7)           \
> >> +             ((d0 << 28) | (d1 << 24) | (d2 << 20) | (d3
> >> << 16) |      \
> >> +              (d4 << 12) | (d5 << 8) | (d6 << 4) | (d7 << 0))
> >> +#define EXYNOS4210_DIV_CPU11(d0, d1,
> >> d2)                           \
> >> +             ((d0 << 8) | (d1 << 4) | (d2 << 0))
> >> +#define EXYNOS4210_CFG_LEN 13
> >> +
> >> +/*
> >> + * parse cpu clock frequency table and auxillary configuration
> >> data from dt
> >> + * for exynos4210 and compatible SoC's.
> >> + */
> >> +static int exynos4210_armclk_cfg_parser(struct device_node *np,
> >> +             struct samsung_cpuclk_freq_table **tbl)
> >> +{
> >> +     struct samsung_cpuclk_freq_table *freq_tbl;
> >> +     struct exynos4210_freq_data *fdata, *t_fdata;
> >> +     unsigned long *freqs, cfg[EXYNOS4210_CFG_LEN];
> >> +     const struct property *prop;
> >> +     unsigned int tbl_sz, i, j;
> >> +     const __be32 *val;
> >> +     int ret;
> >> +
> >> +     prop = of_find_property(np, "arm-frequency-table", NULL);
> >> +     if (!prop)
> >> +             return -EINVAL;
> >> +     if (!prop->value)
> >> +             return -EINVAL;
> >> +     if ((prop->length / sizeof(u32)) % EXYNOS4210_CFG_LEN)
> >
> > Cannot we have the EXYNOS4210_CFG_LEN parsed from DT as well?
> 
> As per Rob's suggestion, the clock divider ration table will be
> removed. So this portion of the code will be reworked.

Ok. Thanks.

> 
> >
> >> +             return -EINVAL;
> >> +     tbl_sz = (prop->length / sizeof(u32)) / EXYNOS4210_CFG_LEN;
> >> +
> >> +     freq_tbl = kzalloc(sizeof(*freq_tbl), GFP_KERNEL);
> >> +     if (!freq_tbl)
> >> +             return -ENOMEM;
> >> +
> >> +     freqs = kzalloc(sizeof(u32) * tbl_sz, GFP_KERNEL);
> >> +     if (!freqs) {
> >> +             ret = -ENOMEM;
> >> +             goto free_freq_tbl;
> >> +     }
> >> +
> >> +     fdata = kzalloc(sizeof(*fdata) * tbl_sz, GFP_KERNEL);
> >> +     if (!fdata) {
> >> +             ret = -ENOMEM;
> >> +             goto free_freqs;
> >> +     }
> >> +     t_fdata = fdata;
> >> +
> >> +     val = prop->value;
> >> +     for (i = 0; i < tbl_sz; i++, fdata++) {
> >> +             for (j = 0; j < EXYNOS4210_CFG_LEN; j++)
> >> +                     cfg[j] = be32_to_cpup(val++);
> >> +             freqs[i] = cfg[0];
> >> +             fdata->parent_freq = cfg[1];
> >
> > Why do we need the separate parent_freq entry here?
> >
> > In the patch 4/7 the freqs (cfg[0]) and parent_freq (cfg[1]) values
> > are the same for all supported devices (at "arm-frequency-table").
> >
> > What is the rationale for having those values duplicated in the DT?
> 
> The intention was to support frequencies which may not be direct
> output of the parent PLL clock. For instance, if the PLL supports
> 200MHz, 400MHz and 600MHz and the CPU clock needs to be set to 300MHz,
> then 600MHz / 2 is a valid clock output for the cpu clock. So this is
> an example where the cpu clock speed is different from its parent
> clock speed.

But shall not this case been handled by CCF internally? 

Is there any Samsung PLL clock, which has such property?

> If possible, I will try and remove the need for this table in the
> next version.

Ok.

> 
> Thanks,
> Thomas.
> 
> >
> >
> >> +             fdata->div0 = EXYNOS4210_DIV_CPU01(cfg[9], cfg[8],
> >> cfg[7],
> >> +                             cfg[6], cfg[5], cfg[4], cfg[3],
> >> cfg[2]);
> >> +             fdata->div1 = EXYNOS4210_DIV_CPU11(cfg[12], cfg[11],
> >> cfg[10]);
> >> +     }
> >> +
> >> +     freq_tbl->freq = freqs;
> >> +     freq_tbl->freq_count = tbl_sz;
> >> +     freq_tbl->data = t_fdata;
> >> +     *tbl = freq_tbl;
> >> +     return 0;
> >> +
> >> +free_freqs:
> >> +     kfree(freqs);
> >> +free_freq_tbl:
> >> +     kfree(freq_tbl);
> >> +     return ret;
> >> +}
> >> +
> >> +static struct samsung_cpuclk_match_data
> >> exynos4210_cpuclk_match_data = {
> >> +     .parser = exynos4210_armclk_cfg_parser,
> >> +     .offset = 0x14200,
> >> +};
> >> +
> >> +static struct samsung_cpuclk_match_data
> >> exynos5250_cpuclk_match_data = {
> >> +     .parser = exynos4210_armclk_cfg_parser,
> >> +     .offset = 0x200,
> >> +};
> >> +
> >> +static const struct of_device_id samsung_clock_ids[] = {
> >> +     { .compatible = "samsung,exynos4210-clock",
> >> +                     .data = &exynos4210_cpuclk_match_data, },
> >> +     { .compatible = "samsung,exynos4412-clock",
> >> +                     .data = &exynos4210_cpuclk_match_data, },
> >> +     { .compatible = "samsung,exynos5250-clock",
> >> +                     .data = &exynos5250_cpuclk_match_data, },
> >> +};
> >> +
> >> +int __init samsung_register_arm_clock(struct device_node *np,
> >> +             unsigned int lookup_id, const char *parent,
> >> void __iomem *base) +{
> >> +     const struct of_device_id *match;
> >> +     struct samsung_cpuclk_freq_table *freq_table;
> >> +     const struct samsung_cpuclk_match_data *data;
> >> +     int ret;
> >> +
> >> +     match = of_match_node(samsung_clock_ids, np);
> >> +     if (!match) {
> >> +             pr_err("%s: could not determine soc type\n",
> >> __func__);
> >> +             return -EINVAL;
> >> +     }
> >> +
> >> +     data = match->data;
> >> +     ret = data->parser(np, &freq_table);
> >> +     if (ret) {
> >> +             pr_err("%s: error %d in parsing arm clock freq
> >> table",
> >> +                                             __func__, ret);
> >> +             return -EINVAL;
> >> +     }
> >> +
> >> +     samsung_cpuclk_register(lookup_id, "armclk", parent,
> >> +             &exynos4210_armclk_clk_ops, freq_table, base, data);
> >> +
> >> +     return 0;
> >> +}
> >> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
> >> index 31b4174..a759330 100644
> >> --- a/drivers/clk/samsung/clk.h
> >> +++ b/drivers/clk/samsung/clk.h
> >> @@ -340,4 +340,7 @@ extern void __init
> >> samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
> >>  extern unsigned long _get_rate(const char *clk_name);
> >>
> >> +extern int __init samsung_register_arm_clock(struct device_node
> >> *np,
> >> +             unsigned int lookup_id, const char *parent, void
> >> __iomem *base); +
> >>  #endif /* __SAMSUNG_CLK_H */
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-01-21 10:25       ` Lukasz Majewski
@ 2014-01-21 10:38         ` Thomas Abraham
  2014-01-21 10:59           ` Lukasz Majewski
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 21, 2014 at 3:55 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> Hi Lukasz,
>>
>> On Mon, Jan 20, 2014 at 1:54 PM, Lukasz Majewski
>> <l.majewski@samsung.com> wrote:
>> > Hi Thomas,
>> >
>> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >>
>> >> The CPU clock provider supplies the clock to the CPU clock domain.
>> >> The composition and organization of the CPU clock provider could
>> >> vary among Exynos SoCs. A CPU clock provider can be composed of
>> >> clock mux, dividers and gates. This patch defines a new clock type
>> >> for CPU clock provider and adds infrastructure to register the CPU
>> >> clock providers for Samsung platforms.
>> >>
>> >> In addition to this, the arm cpu clock provider for Exynos4210 and
>> >> compatible SoCs is instantiated using the new cpu clock type. The
>> >> clock frequency table and the clock configuration data for this
>> >> clock is obtained from device tree. This implementation is
>> >> reusable for Exynos4x12 and Exynos5250 SoCs as well.
>> >>
>> >> Cc: Tomasz Figa <t.figa@samsung.com>
>> >> Cc: Lukasz Majewski <l.majewski@majess.pl>
>> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >> ---
>> >>  drivers/clk/samsung/Makefile  |    2 +-
>> >>  drivers/clk/samsung/clk-cpu.c |  345
>> >> +++++++++++++++++++++++++++++++++++++++++
>> >> drivers/clk/samsung/clk.h     |    3 + 3 files changed, 349
>> >> insertions(+), 1 deletions(-) create mode 100644
>> >> drivers/clk/samsung/clk-cpu.c
>> >>
>> >> diff --git a/drivers/clk/samsung/Makefile
>> >> b/drivers/clk/samsung/Makefile index 8eb4799..e2b453f 100644
>> >> --- a/drivers/clk/samsung/Makefile
>> >> +++ b/drivers/clk/samsung/Makefile
>> >> @@ -2,7 +2,7 @@
>> >>  # Samsung Clock specific Makefile
>> >>  #
>> >>
>> >> -obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o
>> >> +obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o clk-cpu.o
>> >>  obj-$(CONFIG_ARCH_EXYNOS4)   += clk-exynos4.o
>> >>  obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
>> >>  obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
>> >> diff --git a/drivers/clk/samsung/clk-cpu.c
>> >> b/drivers/clk/samsung/clk-cpu.c new file mode 100644
>> >> index 0000000..92fba45
>> >> --- /dev/null
>> >> +++ b/drivers/clk/samsung/clk-cpu.c
>> >> @@ -0,0 +1,345 @@
>> >> +/*
>> >> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
>> >> + * Author: Thomas Abraham <thomas.ab@samsung.com>
>> >> + *
>> >> + * 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 contains the utility functions to register the cpu
>> >> clocks
>> >> + * for samsung platforms.
>> >> +*/
>> >> +
>> >> +#include <linux/errno.h>
>> >> +#include "clk.h"
>> >> +
>> >> +#define SRC_CPU                      0x0
>> >> +#define STAT_CPU             0x200
>> >> +#define DIV_CPU0             0x300
>> >> +#define DIV_CPU1             0x304
>> >> +#define DIV_STAT_CPU0                0x400
>> >> +#define DIV_STAT_CPU1                0x404
>> >> +
>> >> +/**
>> >> + * struct samsung_cpuclk_freq_table: table of frequency supported
>> >> by
>> >> + * a cpu clock and associated data if any.
>> >> + * @freq: points to a table of supported frequencies (in KHz)
>> >> + * @freq_count: number of entries in the frequency table
>> >> + * @data: cpu clock specific data, if any
>> >> + *
>> >> + * This structure holds the frequency options supported by the cpu
>> >> clock in
>> >> + * which this structure is contained. The data pointer is an
>> >> optional data
>> >> + * that can provide any additional configuration options for the
>> >> supported
>> >> + * frequencies. This structure is intended to be reusable for all
>> >> cpu clocks
>> >> + * in Samsung SoC based platforms
>> >> + */
>> >> +struct samsung_cpuclk_freq_table {
>> >> +     const unsigned long     *freq;       /* in KHz */
>> >> +     unsigned long           freq_count;
>> >> +     const void              *data;
>> >> +};
>> >> +
>> >> +/**
>> >> + * struct exynos4210_freq_data: format of auxillary data
>> >> associated with
>> >> + * each frequency supported by the cpu clock for exynos4210.
>> >> + * @parent_freq: The frequency of the parent clock required to
>> >> generate the
>> >> + * supported cpu clock speed.
>> >> + * @div0: value to be programmed in the div_cpu0 register.
>> >> + * @div1: value to be programmed in the div_cpu1 register.
>> >> + *
>> >> + * This structure holds the auxillary configuration data for each
>> >> supported
>> >> + * cpu clock frequency on Exynos4210 and compatible SoCs.
>> >> + */
>> >> +struct exynos4210_freq_data {
>> >> +     unsigned long   parent_freq;
>> >> +     unsigned int    div0;
>> >> +     unsigned int    div1;
>> >> +};
>> >> +
>> >> +/**
>> >> + * struct samsung_cpuclk: information about clock supplied to a
>> >> CPU core.
>> >> + * @hw: handle between ccf and cpu clock.
>> >> + * @ctrl_base: base address of the clock controller.
>> >> + * @offset: offset from the ctrl_base address where the cpu clock
>> >> div/mux
>> >> + *          registers can be accessed.
>> >> + * @parent: clock handle representing the clock output of the
>> >> parent clock.
>> >> + * @freq_table: the frequency table supported by this cpu clock.
>> >> + */
>> >> +struct samsung_cpuclk {
>> >> +     struct clk_hw           hw;
>> >> +     void __iomem            *ctrl_base;
>> >> +     unsigned long           offset;
>> >> +     struct clk              *parent;
>> >> +     const struct samsung_cpuclk_freq_table *freq_table;
>> >> +};
>> >> +
>> >> +#define to_samsung_cpuclk(hw)        container_of(hw, struct
>> >> samsung_cpuclk, hw) +
>> >> +/**
>> >> + * struct samsung_cpuclk_match_data: soc specific data for cpu
>> >> clocks.
>> >> + * @parser: pointer to a function that can parse SoC specific cpu
>> >> clock
>> >> + *   frequency and associated configuration data.
>> >> + * @offset: optional offset from base of clock controller register
>> >> base,
>> >> + *   to be used when accessing clock controller registers
>> >> related to the
>> >> + * cpu clock.
>> >> + * @offset: offset from the ctrl_base address where the cpu clock
>> >> div/mux
>> >> + *   registers can be accessed.
>> >> + */
>> >> +struct samsung_cpuclk_match_data {
>> >> +     int (*parser)(struct device_node *,
>> >> +                     struct samsung_cpuclk_freq_table **);
>> >> +     unsigned int offset;
>> >> +};
>> >> +
>> >> +/* This is a helper function to perform clock rounding for cpu
>> >> clocks. */ +static long samsung_cpuclk_round_rate(struct clk_hw
>> >> *hw,
>> >> +                     unsigned long drate, unsigned long *prate)
>> >> +{
>> >> +     struct samsung_cpuclk *cpuclk = to_samsung_cpuclk(hw);
>> >> +     const struct samsung_cpuclk_freq_table *freq_tbl;
>> >> +     int i;
>> >> +
>> >> +     freq_tbl = cpuclk->freq_table;
>> >> +     drate /= 1000;
>> >> +
>> >> +     for (i = 0; i < freq_tbl->freq_count; i++) {
>> >> +             if (drate >= freq_tbl->freq[i])
>> >> +                     return freq_tbl->freq[i] * 1000;
>> >> +     }
>> >> +     return freq_tbl->freq[i - 1] * 1000;
>> >> +}
>> >> +
>> >> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf)
>> >> + 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0)
>> >> >> 28) & 0xf) + 1) +
>> >> +/*
>> >> + * CPU clock speed for Exynos4210 and compatible SoCs is
>> >> + * parent clock speed / core1_ratio / core2_ratio
>> >> + */
>> >> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw
>> >> *hw,
>> >> +                             unsigned long parent_rate)
>> >> +{
>> >> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
>> >> +     void __iomem *base = armclk->ctrl_base + armclk->offset;
>> >> +
>> >> +     return parent_rate / EXYNOS4210_ARM_DIV1(base) /
>> >> +                             EXYNOS4210_ARM_DIV2(base);
>> >> +}
>> >> +
>> >> +/* set rate callback for cpuclk type on Exynos4210 and similar
>> >> SoCs */ +static int exynos4210_armclk_set_rate(struct clk_hw *hw,
>> >> unsigned long drate,
>> >> +                                     unsigned long prate)
>> >> +{
>> >> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
>> >> +     const struct samsung_cpuclk_freq_table *freq_tbl;
>> >> +     const struct exynos4210_freq_data *freq_data;
>> >> +     unsigned long mux_reg, idx;
>> >> +     void __iomem *base;
>> >> +
>> >> +     if (drate == prate)
>> >> +             return 0;
>> >> +
>> >> +     freq_tbl = armclk->freq_table;
>> >> +     freq_data = freq_tbl->data;
>> >> +     base = armclk->ctrl_base + armclk->offset;
>> >> +
>> >> +     for (idx = 0; idx < freq_tbl->freq_count; idx++, freq_data++)
>> >> +             if ((freq_tbl->freq[idx] * 1000) == drate)
>> >> +                     break;
>> >> +
>> >> +     if (drate < prate) {
>> >> +             mux_reg = readl(base + SRC_CPU);
>> >> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
>> >> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
>> >> +                     ;
>> >> +
>> >> +             clk_set_rate(armclk->parent, drate);
>> >> +     }
>> >> +
>> >> +     writel(freq_data->div0, base + DIV_CPU0);
>> >> +     while (readl(base + DIV_STAT_CPU0) != 0)
>> >> +             ;
>> >> +     writel(freq_data->div1, base + DIV_CPU1);
>> >> +     while (readl(base + DIV_STAT_CPU1) != 0)
>> >> +             ;
>> >> +
>> >> +     if (drate > prate) {
>> >> +             mux_reg = readl(base + SRC_CPU);
>> >> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
>> >> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
>> >> +                     ;
>> >> +
>> >> +             clk_set_rate(armclk->parent, freq_data->parent_freq
>> >> * 1000);
>> >> +     }
>> >> +
>> >> +     mux_reg = readl(base + SRC_CPU);
>> >> +     writel(mux_reg & ~(1 << 16), base + SRC_CPU);
>> >> +     while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
>> >> +                     ;
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +/* clock ops for armclk on Exynos4210 and compatible platforms. */
>> >> +static const struct clk_ops exynos4210_armclk_clk_ops = {
>> >> +     .recalc_rate = exynos4210_armclk_recalc_rate,
>> >> +     .round_rate = samsung_cpuclk_round_rate,
>> >> +     .set_rate = exynos4210_armclk_set_rate,
>> >> +};
>> >> +
>> >> +/* helper function to register a cpu clock */
>> >> +static void __init samsung_cpuclk_register(unsigned int lookup_id,
>> >> +             const char *name, const char *parent, const struct
>> >> clk_ops *ops,
>> >> +             const struct samsung_cpuclk_freq_table *freq_tbl,
>> >> +             void __iomem *reg_base,
>> >> +             const struct samsung_cpuclk_match_data *data)
>> >> +{
>> >> +     struct samsung_cpuclk *cpuclk;
>> >> +     struct clk_init_data init;
>> >> +     struct clk *clk;
>> >> +
>> >> +     cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
>> >> +     if (!cpuclk) {
>> >> +             pr_err("%s: could not allocate memory for cpuclk
>> >> %s\n",
>> >> +                                     __func__, name);
>> >> +             return;
>> >> +     }
>> >> +
>> >> +     init.name = name;
>> >> +     init.flags = CLK_GET_RATE_NOCACHE;
>> >> +     init.parent_names = &parent;
>> >> +     init.num_parents = 1;
>> >> +     init.ops = ops;
>> >> +
>> >> +     cpuclk->hw.init = &init;
>> >> +     cpuclk->ctrl_base = reg_base;
>> >> +     cpuclk->offset = data->offset;
>> >> +     cpuclk->freq_table = freq_tbl;
>> >> +     cpuclk->parent = __clk_lookup(parent);
>> >> +
>> >> +     clk = clk_register(NULL, &cpuclk->hw);
>> >> +     if (IS_ERR(clk)) {
>> >> +             pr_err("%s: could not register cpuclk %s\n",
>> >> __func__,     name);
>> >> +             kfree(cpuclk);
>> >> +             return;
>> >> +     }
>> >> +     samsung_clk_add_lookup(clk, lookup_id);
>> >> +}
>> >> +
>> >> +#define EXYNOS4210_DIV_CPU01(d0, d1, d2, d3, d4, d5, d6,
>> >> d7)           \
>> >> +             ((d0 << 28) | (d1 << 24) | (d2 << 20) | (d3
>> >> << 16) |      \
>> >> +              (d4 << 12) | (d5 << 8) | (d6 << 4) | (d7 << 0))
>> >> +#define EXYNOS4210_DIV_CPU11(d0, d1,
>> >> d2)                           \
>> >> +             ((d0 << 8) | (d1 << 4) | (d2 << 0))
>> >> +#define EXYNOS4210_CFG_LEN 13
>> >> +
>> >> +/*
>> >> + * parse cpu clock frequency table and auxillary configuration
>> >> data from dt
>> >> + * for exynos4210 and compatible SoC's.
>> >> + */
>> >> +static int exynos4210_armclk_cfg_parser(struct device_node *np,
>> >> +             struct samsung_cpuclk_freq_table **tbl)
>> >> +{
>> >> +     struct samsung_cpuclk_freq_table *freq_tbl;
>> >> +     struct exynos4210_freq_data *fdata, *t_fdata;
>> >> +     unsigned long *freqs, cfg[EXYNOS4210_CFG_LEN];
>> >> +     const struct property *prop;
>> >> +     unsigned int tbl_sz, i, j;
>> >> +     const __be32 *val;
>> >> +     int ret;
>> >> +
>> >> +     prop = of_find_property(np, "arm-frequency-table", NULL);
>> >> +     if (!prop)
>> >> +             return -EINVAL;
>> >> +     if (!prop->value)
>> >> +             return -EINVAL;
>> >> +     if ((prop->length / sizeof(u32)) % EXYNOS4210_CFG_LEN)
>> >
>> > Cannot we have the EXYNOS4210_CFG_LEN parsed from DT as well?
>>
>> As per Rob's suggestion, the clock divider ration table will be
>> removed. So this portion of the code will be reworked.
>
> Ok. Thanks.
>
>>
>> >
>> >> +             return -EINVAL;
>> >> +     tbl_sz = (prop->length / sizeof(u32)) / EXYNOS4210_CFG_LEN;
>> >> +
>> >> +     freq_tbl = kzalloc(sizeof(*freq_tbl), GFP_KERNEL);
>> >> +     if (!freq_tbl)
>> >> +             return -ENOMEM;
>> >> +
>> >> +     freqs = kzalloc(sizeof(u32) * tbl_sz, GFP_KERNEL);
>> >> +     if (!freqs) {
>> >> +             ret = -ENOMEM;
>> >> +             goto free_freq_tbl;
>> >> +     }
>> >> +
>> >> +     fdata = kzalloc(sizeof(*fdata) * tbl_sz, GFP_KERNEL);
>> >> +     if (!fdata) {
>> >> +             ret = -ENOMEM;
>> >> +             goto free_freqs;
>> >> +     }
>> >> +     t_fdata = fdata;
>> >> +
>> >> +     val = prop->value;
>> >> +     for (i = 0; i < tbl_sz; i++, fdata++) {
>> >> +             for (j = 0; j < EXYNOS4210_CFG_LEN; j++)
>> >> +                     cfg[j] = be32_to_cpup(val++);
>> >> +             freqs[i] = cfg[0];
>> >> +             fdata->parent_freq = cfg[1];
>> >
>> > Why do we need the separate parent_freq entry here?
>> >
>> > In the patch 4/7 the freqs (cfg[0]) and parent_freq (cfg[1]) values
>> > are the same for all supported devices (at "arm-frequency-table").
>> >
>> > What is the rationale for having those values duplicated in the DT?
>>
>> The intention was to support frequencies which may not be direct
>> output of the parent PLL clock. For instance, if the PLL supports
>> 200MHz, 400MHz and 600MHz and the CPU clock needs to be set to 300MHz,
>> then 600MHz / 2 is a valid clock output for the cpu clock. So this is
>> an example where the cpu clock speed is different from its parent
>> clock speed.
>
> But shall not this case been handled by CCF internally?

The divider which actually can divide the PLL clock output is now part
of the larger cpu clock type. So it is the implementation of the
set_rate function of the cpu clock that has to handle this division.
So there is no core CCF support to handle this.

>
> Is there any Samsung PLL clock, which has such property?

Yes, this functionality is available on all Exynos SoCs but it is not
a Samsung PLL clock property. The PLL clock output can optionally be
divided and then used as arm clock output.

>
>> If possible, I will try and remove the need for this table in the
>> next version.
>
> Ok.

On second thoughts, it looks possible to get rid of this table and I
am testing with this approach now.

>
>>
>> Thanks,
>> Thomas.
>>
>> >
>> >
>> >> +             fdata->div0 = EXYNOS4210_DIV_CPU01(cfg[9], cfg[8],
>> >> cfg[7],
>> >> +                             cfg[6], cfg[5], cfg[4], cfg[3],
>> >> cfg[2]);
>> >> +             fdata->div1 = EXYNOS4210_DIV_CPU11(cfg[12], cfg[11],
>> >> cfg[10]);
>> >> +     }
>> >> +
>> >> +     freq_tbl->freq = freqs;
>> >> +     freq_tbl->freq_count = tbl_sz;
>> >> +     freq_tbl->data = t_fdata;
>> >> +     *tbl = freq_tbl;
>> >> +     return 0;
>> >> +
>> >> +free_freqs:
>> >> +     kfree(freqs);
>> >> +free_freq_tbl:
>> >> +     kfree(freq_tbl);
>> >> +     return ret;
>> >> +}
>> >> +
>> >> +static struct samsung_cpuclk_match_data
>> >> exynos4210_cpuclk_match_data = {
>> >> +     .parser = exynos4210_armclk_cfg_parser,
>> >> +     .offset = 0x14200,
>> >> +};
>> >> +
>> >> +static struct samsung_cpuclk_match_data
>> >> exynos5250_cpuclk_match_data = {
>> >> +     .parser = exynos4210_armclk_cfg_parser,
>> >> +     .offset = 0x200,
>> >> +};
>> >> +
>> >> +static const struct of_device_id samsung_clock_ids[] = {
>> >> +     { .compatible = "samsung,exynos4210-clock",
>> >> +                     .data = &exynos4210_cpuclk_match_data, },
>> >> +     { .compatible = "samsung,exynos4412-clock",
>> >> +                     .data = &exynos4210_cpuclk_match_data, },
>> >> +     { .compatible = "samsung,exynos5250-clock",
>> >> +                     .data = &exynos5250_cpuclk_match_data, },
>> >> +};
>> >> +
>> >> +int __init samsung_register_arm_clock(struct device_node *np,
>> >> +             unsigned int lookup_id, const char *parent,
>> >> void __iomem *base) +{
>> >> +     const struct of_device_id *match;
>> >> +     struct samsung_cpuclk_freq_table *freq_table;
>> >> +     const struct samsung_cpuclk_match_data *data;
>> >> +     int ret;
>> >> +
>> >> +     match = of_match_node(samsung_clock_ids, np);
>> >> +     if (!match) {
>> >> +             pr_err("%s: could not determine soc type\n",
>> >> __func__);
>> >> +             return -EINVAL;
>> >> +     }
>> >> +
>> >> +     data = match->data;
>> >> +     ret = data->parser(np, &freq_table);
>> >> +     if (ret) {
>> >> +             pr_err("%s: error %d in parsing arm clock freq
>> >> table",
>> >> +                                             __func__, ret);
>> >> +             return -EINVAL;
>> >> +     }
>> >> +
>> >> +     samsung_cpuclk_register(lookup_id, "armclk", parent,
>> >> +             &exynos4210_armclk_clk_ops, freq_table, base, data);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
>> >> index 31b4174..a759330 100644
>> >> --- a/drivers/clk/samsung/clk.h
>> >> +++ b/drivers/clk/samsung/clk.h
>> >> @@ -340,4 +340,7 @@ extern void __init
>> >> samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
>> >>  extern unsigned long _get_rate(const char *clk_name);
>> >>
>> >> +extern int __init samsung_register_arm_clock(struct device_node
>> >> *np,
>> >> +             unsigned int lookup_id, const char *parent, void
>> >> __iomem *base); +
>> >>  #endif /* __SAMSUNG_CLK_H */
>> >
>> >
>> >
>> > --
>> > Best regards,
>> >
>> > Lukasz Majewski
>> >
>> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-01-21  7:52     ` Thomas Abraham
@ 2014-01-21 10:38       ` Lukasz Majewski
  2014-01-21 11:15         ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-21 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> On Mon, Jan 20, 2014 at 1:17 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> With the addition of the new Samsung specific cpu-clock type, the
> >> arm clock can be represented as a cpu-clock type and the
> >> independent clock blocks that made up the arm clock can be removed.
> >>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> ---
> >>  .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
> >>  drivers/clk/samsung/clk-exynos4.c                  |   11
> >> +++++------ drivers/clk/samsung/clk-exynos5250.c
> >> |    8 ++++---- include/dt-bindings/clock/exynos5250.h
> >> |    1 + 4 files changed, 11 insertions(+), 10 deletions(-)
> >>
> >> diff --git
> >> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> >> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> >> index 99eae9c..acf867a 100644 ---
> >> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt +++
> >> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt @@
> >> -38,6 +38,7 @@ clock which they consume.
> >> ---------------------------- fin_pll            1
> >> +  armclk             12
> >>
> >>    [Clock Gate for Special Clocks]
> >>
> >> diff --git a/drivers/clk/samsung/clk-exynos4.c
> >> b/drivers/clk/samsung/clk-exynos4.c index 010f071..efcf4a3 100644
> >> --- a/drivers/clk/samsung/clk-exynos4.c
> >> +++ b/drivers/clk/samsung/clk-exynos4.c
> >> @@ -437,8 +437,6 @@ static struct samsung_mux_clock
> >> exynos4x12_mux_clks[] __initdata = {
> >>  /* list of divider clocks supported in all exynos4 soc's */
> >>  static struct samsung_div_clock exynos4_div_clks[] __initdata = {
> >> -     DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3),
> >> -     DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3),
> >>       DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
> >>       DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
> >>       DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
> >> @@ -484,8 +482,8 @@ static struct samsung_div_clock
> >> exynos4_div_clks[] __initdata = { DIV(0, "div_spi_pre2",
> >> "div_spi2", DIV_PERIL2, 8, 8), DIV(0, "div_audio1", "mout_audio1",
> >> DIV_PERIL4, 0, 4), DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4,
> >> 16, 4),
> >> -     DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
> >> -     DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
> >> 3),
> >> +     DIV_F(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
> >> 3,
> >> +                     CLK_GET_RATE_NOCACHE, 0),
> >>       DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
> >>                       CLK_SET_RATE_PARENT, 0),
> >>       DIV_F(0, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
> >> @@ -870,7 +868,6 @@ static struct samsung_gate_clock
> >> exynos4x12_gate_clks[] __initdata = {
> >>  static struct samsung_clock_alias exynos4_aliases[] __initdata = {
> >>       ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
> >> -     ALIAS(CLK_ARM_CLK, NULL, "armclk"),
> >>       ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"),
> >>  };
> >>
> >> @@ -1125,12 +1122,14 @@ static void __init exynos4_clk_init(struct
> >> device_node *np, samsung_clk_register_alias(exynos4_aliases,
> >>                       ARRAY_SIZE(exynos4_aliases));
> >>
> >> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
> >> reg_base); +
> >
> > I've got some doubts about allowing only the "mout_apll" clock to
> > be the only parent for armclk Samsung clock.
> >
> > For the Exynos4412 it is also valid to have SCLK_MPLL_USER_C [*] as
> > a parent for this clock.
> >
> > The problem is that you are reparenting the armclk to [*] with the
> > register modification - no CCF involved.
> 
> The MUX_CORE mux is part of the larger cpu clock type and not
> registered as a separate mux clock with CCF. So I would like to know
> if there are any potential issues you see if this mux clock is
> internally managed within the set_rate of the larger cpu clock type.

So the large opaque clock (armclk) starts with inputs to MUX_CORE (and
embrace this MUX as well)?

If yes, then I don't mind if it is solely managed inside the armclk.

This however allows the armclk to be fed from mout_apll[*] and
sclk_mpll__user_c[**]. And this would be nice if reflected in the code.

> 
> >
> > I just would like to know if this is yours design decision or
> > something, that we have overlooked in the v1 of this patch series.
> 
> I did overlook this one. This will be fixed in the next version by
> ensuring that the dividers for SCLK_HPM clock will be updated only if
> mout_apll is the parent of the MUX_HPM clock mux.

Shall not they be updated if whatever connected to the MUX_HPM
([*] and [**]) changes?

> 
> Thanks,
> Thomas.
> 
> >
> >>       pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
> >>               "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk =
> >> %ld\n", exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
> >>               _get_rate("sclk_apll"),
> >> _get_rate("sclk_mpll"), _get_rate("sclk_epll"),
> >> _get_rate("sclk_vpll"),
> >> -             _get_rate("arm_clk"));
> >> +             _get_rate("armclk"));
> >>  }
> >>
> >>
> >> diff --git a/drivers/clk/samsung/clk-exynos5250.c
> >> b/drivers/clk/samsung/clk-exynos5250.c index ff4beeb..487be36
> >> 100644 --- a/drivers/clk/samsung/clk-exynos5250.c
> >> +++ b/drivers/clk/samsung/clk-exynos5250.c
> >> @@ -298,9 +298,8 @@ static struct samsung_div_clock
> >> exynos5250_div_clks[] __initdata = { /*
> >>        * CMU_CPU
> >>        */
> >> -     DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
> >> -     DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
> >> -     DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3, "armclk"),
> >> +     DIV_F(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
> >> +                     CLK_GET_RATE_NOCACHE, 0),
> >>
> >>       /*
> >>        * CMU_TOP
> >> @@ -684,8 +683,9 @@ static void __init exynos5250_clk_init(struct
> >> device_node *np) ARRAY_SIZE(exynos5250_div_clks));
> >>       samsung_clk_register_gate(exynos5250_gate_clks,
> >>                       ARRAY_SIZE(exynos5250_gate_clks));
> >> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
> >> reg_base);
> >>       pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
> >> -                     _get_rate("div_arm2"));
> >> +                     _get_rate("armclk"));
> >>  }
> >>  CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock",
> >> exynos5250_clk_init); diff --git
> >> a/include/dt-bindings/clock/exynos5250.h
> >> b/include/dt-bindings/clock/exynos5250.h index 922f2dc..59a10fb
> >> 100644 --- a/include/dt-bindings/clock/exynos5250.h +++
> >> b/include/dt-bindings/clock/exynos5250.h @@ -21,6 +21,7 @@
> >>  #define CLK_FOUT_CPLL                6
> >>  #define CLK_FOUT_EPLL                7
> >>  #define CLK_FOUT_VPLL                8
> >> +#define CLK_ARM_CLK          12
> >>
> >>  /* gate for special clocks (sclk) */
> >>  #define CLK_SCLK_CAM_BAYER   128
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-01-21 10:38         ` Thomas Abraham
@ 2014-01-21 10:59           ` Lukasz Majewski
  0 siblings, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-21 10:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> On Tue, Jan 21, 2014 at 3:55 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> >> Hi Lukasz,
> >>
> >> On Mon, Jan 20, 2014 at 1:54 PM, Lukasz Majewski
> >> <l.majewski@samsung.com> wrote:
> >> > Hi Thomas,
> >> >
> >> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >> >>
> >> >> The CPU clock provider supplies the clock to the CPU clock
> >> >> domain. The composition and organization of the CPU clock
> >> >> provider could vary among Exynos SoCs. A CPU clock provider can
> >> >> be composed of clock mux, dividers and gates. This patch
> >> >> defines a new clock type for CPU clock provider and adds
> >> >> infrastructure to register the CPU clock providers for Samsung
> >> >> platforms.
> >> >>
> >> >> In addition to this, the arm cpu clock provider for Exynos4210
> >> >> and compatible SoCs is instantiated using the new cpu clock
> >> >> type. The clock frequency table and the clock configuration
> >> >> data for this clock is obtained from device tree. This
> >> >> implementation is reusable for Exynos4x12 and Exynos5250 SoCs
> >> >> as well.
> >> >>
> >> >> Cc: Tomasz Figa <t.figa@samsung.com>
> >> >> Cc: Lukasz Majewski <l.majewski@majess.pl>
> >> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> >> ---
> >> >>  drivers/clk/samsung/Makefile  |    2 +-
> >> >>  drivers/clk/samsung/clk-cpu.c |  345
> >> >> +++++++++++++++++++++++++++++++++++++++++
> >> >> drivers/clk/samsung/clk.h     |    3 + 3 files changed, 349
> >> >> insertions(+), 1 deletions(-) create mode 100644
> >> >> drivers/clk/samsung/clk-cpu.c
> >> >>
> >> >> diff --git a/drivers/clk/samsung/Makefile
> >> >> b/drivers/clk/samsung/Makefile index 8eb4799..e2b453f 100644
> >> >> --- a/drivers/clk/samsung/Makefile
> >> >> +++ b/drivers/clk/samsung/Makefile
> >> >> @@ -2,7 +2,7 @@
> >> >>  # Samsung Clock specific Makefile
> >> >>  #
> >> >>
> >> >> -obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o
> >> >> +obj-$(CONFIG_COMMON_CLK)     += clk.o clk-pll.o clk-cpu.o
> >> >>  obj-$(CONFIG_ARCH_EXYNOS4)   += clk-exynos4.o
> >> >>  obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
> >> >>  obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
> >> >> diff --git a/drivers/clk/samsung/clk-cpu.c
> >> >> b/drivers/clk/samsung/clk-cpu.c new file mode 100644
> >> >> index 0000000..92fba45
> >> >> --- /dev/null
> >> >> +++ b/drivers/clk/samsung/clk-cpu.c
> >> >> @@ -0,0 +1,345 @@
> >> >> +/*
> >> >> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> >> >> + * Author: Thomas Abraham <thomas.ab@samsung.com>
> >> >> + *
> >> >> + * 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 contains the utility functions to register the cpu
> >> >> clocks
> >> >> + * for samsung platforms.
> >> >> +*/
> >> >> +
> >> >> +#include <linux/errno.h>
> >> >> +#include "clk.h"
> >> >> +
> >> >> +#define SRC_CPU                      0x0
> >> >> +#define STAT_CPU             0x200
> >> >> +#define DIV_CPU0             0x300
> >> >> +#define DIV_CPU1             0x304
> >> >> +#define DIV_STAT_CPU0                0x400
> >> >> +#define DIV_STAT_CPU1                0x404
> >> >> +
> >> >> +/**
> >> >> + * struct samsung_cpuclk_freq_table: table of frequency
> >> >> supported by
> >> >> + * a cpu clock and associated data if any.
> >> >> + * @freq: points to a table of supported frequencies (in KHz)
> >> >> + * @freq_count: number of entries in the frequency table
> >> >> + * @data: cpu clock specific data, if any
> >> >> + *
> >> >> + * This structure holds the frequency options supported by the
> >> >> cpu clock in
> >> >> + * which this structure is contained. The data pointer is an
> >> >> optional data
> >> >> + * that can provide any additional configuration options for
> >> >> the supported
> >> >> + * frequencies. This structure is intended to be reusable for
> >> >> all cpu clocks
> >> >> + * in Samsung SoC based platforms
> >> >> + */
> >> >> +struct samsung_cpuclk_freq_table {
> >> >> +     const unsigned long     *freq;       /* in KHz */
> >> >> +     unsigned long           freq_count;
> >> >> +     const void              *data;
> >> >> +};
> >> >> +
> >> >> +/**
> >> >> + * struct exynos4210_freq_data: format of auxillary data
> >> >> associated with
> >> >> + * each frequency supported by the cpu clock for exynos4210.
> >> >> + * @parent_freq: The frequency of the parent clock required to
> >> >> generate the
> >> >> + * supported cpu clock speed.
> >> >> + * @div0: value to be programmed in the div_cpu0 register.
> >> >> + * @div1: value to be programmed in the div_cpu1 register.
> >> >> + *
> >> >> + * This structure holds the auxillary configuration data for
> >> >> each supported
> >> >> + * cpu clock frequency on Exynos4210 and compatible SoCs.
> >> >> + */
> >> >> +struct exynos4210_freq_data {
> >> >> +     unsigned long   parent_freq;
> >> >> +     unsigned int    div0;
> >> >> +     unsigned int    div1;
> >> >> +};
> >> >> +
> >> >> +/**
> >> >> + * struct samsung_cpuclk: information about clock supplied to a
> >> >> CPU core.
> >> >> + * @hw: handle between ccf and cpu clock.
> >> >> + * @ctrl_base: base address of the clock controller.
> >> >> + * @offset: offset from the ctrl_base address where the cpu
> >> >> clock div/mux
> >> >> + *          registers can be accessed.
> >> >> + * @parent: clock handle representing the clock output of the
> >> >> parent clock.
> >> >> + * @freq_table: the frequency table supported by this cpu
> >> >> clock.
> >> >> + */
> >> >> +struct samsung_cpuclk {
> >> >> +     struct clk_hw           hw;
> >> >> +     void __iomem            *ctrl_base;
> >> >> +     unsigned long           offset;
> >> >> +     struct clk              *parent;
> >> >> +     const struct samsung_cpuclk_freq_table *freq_table;
> >> >> +};
> >> >> +
> >> >> +#define to_samsung_cpuclk(hw)        container_of(hw, struct
> >> >> samsung_cpuclk, hw) +
> >> >> +/**
> >> >> + * struct samsung_cpuclk_match_data: soc specific data for cpu
> >> >> clocks.
> >> >> + * @parser: pointer to a function that can parse SoC specific
> >> >> cpu clock
> >> >> + *   frequency and associated configuration data.
> >> >> + * @offset: optional offset from base of clock controller
> >> >> register base,
> >> >> + *   to be used when accessing clock controller registers
> >> >> related to the
> >> >> + * cpu clock.
> >> >> + * @offset: offset from the ctrl_base address where the cpu
> >> >> clock div/mux
> >> >> + *   registers can be accessed.
> >> >> + */
> >> >> +struct samsung_cpuclk_match_data {
> >> >> +     int (*parser)(struct device_node *,
> >> >> +                     struct samsung_cpuclk_freq_table **);
> >> >> +     unsigned int offset;
> >> >> +};
> >> >> +
> >> >> +/* This is a helper function to perform clock rounding for cpu
> >> >> clocks. */ +static long samsung_cpuclk_round_rate(struct clk_hw
> >> >> *hw,
> >> >> +                     unsigned long drate, unsigned long *prate)
> >> >> +{
> >> >> +     struct samsung_cpuclk *cpuclk = to_samsung_cpuclk(hw);
> >> >> +     const struct samsung_cpuclk_freq_table *freq_tbl;
> >> >> +     int i;
> >> >> +
> >> >> +     freq_tbl = cpuclk->freq_table;
> >> >> +     drate /= 1000;
> >> >> +
> >> >> +     for (i = 0; i < freq_tbl->freq_count; i++) {
> >> >> +             if (drate >= freq_tbl->freq[i])
> >> >> +                     return freq_tbl->freq[i] * 1000;
> >> >> +     }
> >> >> +     return freq_tbl->freq[i - 1] * 1000;
> >> >> +}
> >> >> +
> >> >> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) &
> >> >> 0xf)
> >> >> + 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base +
> >> >> DIV_CPU0)
> >> >> >> 28) & 0xf) + 1) +
> >> >> +/*
> >> >> + * CPU clock speed for Exynos4210 and compatible SoCs is
> >> >> + * parent clock speed / core1_ratio / core2_ratio
> >> >> + */
> >> >> +static unsigned long exynos4210_armclk_recalc_rate(struct
> >> >> clk_hw *hw,
> >> >> +                             unsigned long parent_rate)
> >> >> +{
> >> >> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
> >> >> +     void __iomem *base = armclk->ctrl_base + armclk->offset;
> >> >> +
> >> >> +     return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> >> >> +                             EXYNOS4210_ARM_DIV2(base);
> >> >> +}
> >> >> +
> >> >> +/* set rate callback for cpuclk type on Exynos4210 and similar
> >> >> SoCs */ +static int exynos4210_armclk_set_rate(struct clk_hw
> >> >> *hw, unsigned long drate,
> >> >> +                                     unsigned long prate)
> >> >> +{
> >> >> +     struct samsung_cpuclk *armclk = to_samsung_cpuclk(hw);
> >> >> +     const struct samsung_cpuclk_freq_table *freq_tbl;
> >> >> +     const struct exynos4210_freq_data *freq_data;
> >> >> +     unsigned long mux_reg, idx;
> >> >> +     void __iomem *base;
> >> >> +
> >> >> +     if (drate == prate)
> >> >> +             return 0;
> >> >> +
> >> >> +     freq_tbl = armclk->freq_table;
> >> >> +     freq_data = freq_tbl->data;
> >> >> +     base = armclk->ctrl_base + armclk->offset;
> >> >> +
> >> >> +     for (idx = 0; idx < freq_tbl->freq_count; idx++,
> >> >> freq_data++)
> >> >> +             if ((freq_tbl->freq[idx] * 1000) == drate)
> >> >> +                     break;
> >> >> +
> >> >> +     if (drate < prate) {
> >> >> +             mux_reg = readl(base + SRC_CPU);
> >> >> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
> >> >> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) !=
> >> >> 2)
> >> >> +                     ;
> >> >> +
> >> >> +             clk_set_rate(armclk->parent, drate);
> >> >> +     }
> >> >> +
> >> >> +     writel(freq_data->div0, base + DIV_CPU0);
> >> >> +     while (readl(base + DIV_STAT_CPU0) != 0)
> >> >> +             ;
> >> >> +     writel(freq_data->div1, base + DIV_CPU1);
> >> >> +     while (readl(base + DIV_STAT_CPU1) != 0)
> >> >> +             ;
> >> >> +
> >> >> +     if (drate > prate) {
> >> >> +             mux_reg = readl(base + SRC_CPU);
> >> >> +             writel(mux_reg | (1 << 16), base + SRC_CPU);
> >> >> +             while (((readl(base + STAT_CPU) >> 16) & 0x7) !=
> >> >> 2)
> >> >> +                     ;
> >> >> +
> >> >> +             clk_set_rate(armclk->parent,
> >> >> freq_data->parent_freq
> >> >> * 1000);
> >> >> +     }
> >> >> +
> >> >> +     mux_reg = readl(base + SRC_CPU);
> >> >> +     writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> >> >> +     while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> >> >> +                     ;
> >> >> +     return 0;
> >> >> +}
> >> >> +
> >> >> +/* clock ops for armclk on Exynos4210 and compatible
> >> >> platforms. */ +static const struct clk_ops
> >> >> exynos4210_armclk_clk_ops = {
> >> >> +     .recalc_rate = exynos4210_armclk_recalc_rate,
> >> >> +     .round_rate = samsung_cpuclk_round_rate,
> >> >> +     .set_rate = exynos4210_armclk_set_rate,
> >> >> +};
> >> >> +
> >> >> +/* helper function to register a cpu clock */
> >> >> +static void __init samsung_cpuclk_register(unsigned int
> >> >> lookup_id,
> >> >> +             const char *name, const char *parent, const struct
> >> >> clk_ops *ops,
> >> >> +             const struct samsung_cpuclk_freq_table *freq_tbl,
> >> >> +             void __iomem *reg_base,
> >> >> +             const struct samsung_cpuclk_match_data *data)
> >> >> +{
> >> >> +     struct samsung_cpuclk *cpuclk;
> >> >> +     struct clk_init_data init;
> >> >> +     struct clk *clk;
> >> >> +
> >> >> +     cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> >> >> +     if (!cpuclk) {
> >> >> +             pr_err("%s: could not allocate memory for cpuclk
> >> >> %s\n",
> >> >> +                                     __func__, name);
> >> >> +             return;
> >> >> +     }
> >> >> +
> >> >> +     init.name = name;
> >> >> +     init.flags = CLK_GET_RATE_NOCACHE;
> >> >> +     init.parent_names = &parent;
> >> >> +     init.num_parents = 1;
> >> >> +     init.ops = ops;
> >> >> +
> >> >> +     cpuclk->hw.init = &init;
> >> >> +     cpuclk->ctrl_base = reg_base;
> >> >> +     cpuclk->offset = data->offset;
> >> >> +     cpuclk->freq_table = freq_tbl;
> >> >> +     cpuclk->parent = __clk_lookup(parent);
> >> >> +
> >> >> +     clk = clk_register(NULL, &cpuclk->hw);
> >> >> +     if (IS_ERR(clk)) {
> >> >> +             pr_err("%s: could not register cpuclk %s\n",
> >> >> __func__,     name);
> >> >> +             kfree(cpuclk);
> >> >> +             return;
> >> >> +     }
> >> >> +     samsung_clk_add_lookup(clk, lookup_id);
> >> >> +}
> >> >> +
> >> >> +#define EXYNOS4210_DIV_CPU01(d0, d1, d2, d3, d4, d5, d6,
> >> >> d7)           \
> >> >> +             ((d0 << 28) | (d1 << 24) | (d2 << 20) | (d3
> >> >> << 16) |      \
> >> >> +              (d4 << 12) | (d5 << 8) | (d6 << 4) | (d7 << 0))
> >> >> +#define EXYNOS4210_DIV_CPU11(d0, d1,
> >> >> d2)                           \
> >> >> +             ((d0 << 8) | (d1 << 4) | (d2 << 0))
> >> >> +#define EXYNOS4210_CFG_LEN 13
> >> >> +
> >> >> +/*
> >> >> + * parse cpu clock frequency table and auxillary configuration
> >> >> data from dt
> >> >> + * for exynos4210 and compatible SoC's.
> >> >> + */
> >> >> +static int exynos4210_armclk_cfg_parser(struct device_node *np,
> >> >> +             struct samsung_cpuclk_freq_table **tbl)
> >> >> +{
> >> >> +     struct samsung_cpuclk_freq_table *freq_tbl;
> >> >> +     struct exynos4210_freq_data *fdata, *t_fdata;
> >> >> +     unsigned long *freqs, cfg[EXYNOS4210_CFG_LEN];
> >> >> +     const struct property *prop;
> >> >> +     unsigned int tbl_sz, i, j;
> >> >> +     const __be32 *val;
> >> >> +     int ret;
> >> >> +
> >> >> +     prop = of_find_property(np, "arm-frequency-table", NULL);
> >> >> +     if (!prop)
> >> >> +             return -EINVAL;
> >> >> +     if (!prop->value)
> >> >> +             return -EINVAL;
> >> >> +     if ((prop->length / sizeof(u32)) % EXYNOS4210_CFG_LEN)
> >> >
> >> > Cannot we have the EXYNOS4210_CFG_LEN parsed from DT as well?
> >>
> >> As per Rob's suggestion, the clock divider ration table will be
> >> removed. So this portion of the code will be reworked.
> >
> > Ok. Thanks.
> >
> >>
> >> >
> >> >> +             return -EINVAL;
> >> >> +     tbl_sz = (prop->length / sizeof(u32)) /
> >> >> EXYNOS4210_CFG_LEN; +
> >> >> +     freq_tbl = kzalloc(sizeof(*freq_tbl), GFP_KERNEL);
> >> >> +     if (!freq_tbl)
> >> >> +             return -ENOMEM;
> >> >> +
> >> >> +     freqs = kzalloc(sizeof(u32) * tbl_sz, GFP_KERNEL);
> >> >> +     if (!freqs) {
> >> >> +             ret = -ENOMEM;
> >> >> +             goto free_freq_tbl;
> >> >> +     }
> >> >> +
> >> >> +     fdata = kzalloc(sizeof(*fdata) * tbl_sz, GFP_KERNEL);
> >> >> +     if (!fdata) {
> >> >> +             ret = -ENOMEM;
> >> >> +             goto free_freqs;
> >> >> +     }
> >> >> +     t_fdata = fdata;
> >> >> +
> >> >> +     val = prop->value;
> >> >> +     for (i = 0; i < tbl_sz; i++, fdata++) {
> >> >> +             for (j = 0; j < EXYNOS4210_CFG_LEN; j++)
> >> >> +                     cfg[j] = be32_to_cpup(val++);
> >> >> +             freqs[i] = cfg[0];
> >> >> +             fdata->parent_freq = cfg[1];
> >> >
> >> > Why do we need the separate parent_freq entry here?
> >> >
> >> > In the patch 4/7 the freqs (cfg[0]) and parent_freq (cfg[1])
> >> > values are the same for all supported devices (at
> >> > "arm-frequency-table").
> >> >
> >> > What is the rationale for having those values duplicated in the
> >> > DT?
> >>
> >> The intention was to support frequencies which may not be direct
> >> output of the parent PLL clock. For instance, if the PLL supports
> >> 200MHz, 400MHz and 600MHz and the CPU clock needs to be set to
> >> 300MHz, then 600MHz / 2 is a valid clock output for the cpu clock.
	^^^^^^^^^^^^^^^^^^^^ [1]

> >> So this is an example where the cpu clock speed is different from
> >> its parent clock speed.
> >
> > But shall not this case been handled by CCF internally?
> 
> The divider which actually can divide the PLL clock output is now part
> of the larger cpu clock type. So it is the implementation of the
> set_rate function of the cpu clock that has to handle this division.
> So there is no core CCF support to handle this.

I rather thought about the situation you brought up [1].

I agree with the above statement, that it shall be divided internally
(with use of DIV_CORE and DIV_CORE2).

> 
> >
> > Is there any Samsung PLL clock, which has such property?
> 
> Yes, this functionality is available on all Exynos SoCs but it is not
> a Samsung PLL clock property.

So the example [1] cannot be applied to PLLs to Samsung SOCs?

> The PLL clock output can optionally be
> divided and then used as arm clock output.

It will be divided by DIV_CORE and DIV_CORE2, which will be done
internally (at .set_rate) at "armclk".

> 
> >
> >> If possible, I will try and remove the need for this table in the
> >> next version.
> >
> > Ok.
> 
> On second thoughts, it looks possible to get rid of this table and I
> am testing with this approach now.

Ok, thanks.

> 
> >
> >>
> >> Thanks,
> >> Thomas.
> >>
> >> >
> >> >
> >> >> +             fdata->div0 = EXYNOS4210_DIV_CPU01(cfg[9], cfg[8],
> >> >> cfg[7],
> >> >> +                             cfg[6], cfg[5], cfg[4], cfg[3],
> >> >> cfg[2]);
> >> >> +             fdata->div1 = EXYNOS4210_DIV_CPU11(cfg[12],
> >> >> cfg[11], cfg[10]);
> >> >> +     }
> >> >> +
> >> >> +     freq_tbl->freq = freqs;
> >> >> +     freq_tbl->freq_count = tbl_sz;
> >> >> +     freq_tbl->data = t_fdata;
> >> >> +     *tbl = freq_tbl;
> >> >> +     return 0;
> >> >> +
> >> >> +free_freqs:
> >> >> +     kfree(freqs);
> >> >> +free_freq_tbl:
> >> >> +     kfree(freq_tbl);
> >> >> +     return ret;
> >> >> +}
> >> >> +
> >> >> +static struct samsung_cpuclk_match_data
> >> >> exynos4210_cpuclk_match_data = {
> >> >> +     .parser = exynos4210_armclk_cfg_parser,
> >> >> +     .offset = 0x14200,
> >> >> +};
> >> >> +
> >> >> +static struct samsung_cpuclk_match_data
> >> >> exynos5250_cpuclk_match_data = {
> >> >> +     .parser = exynos4210_armclk_cfg_parser,
> >> >> +     .offset = 0x200,
> >> >> +};
> >> >> +
> >> >> +static const struct of_device_id samsung_clock_ids[] = {
> >> >> +     { .compatible = "samsung,exynos4210-clock",
> >> >> +                     .data = &exynos4210_cpuclk_match_data, },
> >> >> +     { .compatible = "samsung,exynos4412-clock",
> >> >> +                     .data = &exynos4210_cpuclk_match_data, },
> >> >> +     { .compatible = "samsung,exynos5250-clock",
> >> >> +                     .data = &exynos5250_cpuclk_match_data, },
> >> >> +};
> >> >> +
> >> >> +int __init samsung_register_arm_clock(struct device_node *np,
> >> >> +             unsigned int lookup_id, const char *parent,
> >> >> void __iomem *base) +{
> >> >> +     const struct of_device_id *match;
> >> >> +     struct samsung_cpuclk_freq_table *freq_table;
> >> >> +     const struct samsung_cpuclk_match_data *data;
> >> >> +     int ret;
> >> >> +
> >> >> +     match = of_match_node(samsung_clock_ids, np);
> >> >> +     if (!match) {
> >> >> +             pr_err("%s: could not determine soc type\n",
> >> >> __func__);
> >> >> +             return -EINVAL;
> >> >> +     }
> >> >> +
> >> >> +     data = match->data;
> >> >> +     ret = data->parser(np, &freq_table);
> >> >> +     if (ret) {
> >> >> +             pr_err("%s: error %d in parsing arm clock freq
> >> >> table",
> >> >> +                                             __func__, ret);
> >> >> +             return -EINVAL;
> >> >> +     }
> >> >> +
> >> >> +     samsung_cpuclk_register(lookup_id, "armclk", parent,
> >> >> +             &exynos4210_armclk_clk_ops, freq_table, base,
> >> >> data); +
> >> >> +     return 0;
> >> >> +}
> >> >> diff --git a/drivers/clk/samsung/clk.h
> >> >> b/drivers/clk/samsung/clk.h index 31b4174..a759330 100644
> >> >> --- a/drivers/clk/samsung/clk.h
> >> >> +++ b/drivers/clk/samsung/clk.h
> >> >> @@ -340,4 +340,7 @@ extern void __init
> >> >> samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
> >> >>  extern unsigned long _get_rate(const char *clk_name);
> >> >>
> >> >> +extern int __init samsung_register_arm_clock(struct device_node
> >> >> *np,
> >> >> +             unsigned int lookup_id, const char *parent, void
> >> >> __iomem *base); +
> >> >>  #endif /* __SAMSUNG_CLK_H */
> >> >
> >> >
> >> >
> >> > --
> >> > Best regards,
> >> >
> >> > Lukasz Majewski
> >> >
> >> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-01-21 10:38       ` Lukasz Majewski
@ 2014-01-21 11:15         ` Thomas Abraham
  2014-01-21 11:42           ` Lukasz Majewski
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-21 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Tue, Jan 21, 2014 at 4:08 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> On Mon, Jan 20, 2014 at 1:17 PM, Lukasz Majewski
>> <l.majewski@samsung.com> wrote:
>> > Hi Thomas,
>> >
>> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >>
>> >> With the addition of the new Samsung specific cpu-clock type, the
>> >> arm clock can be represented as a cpu-clock type and the
>> >> independent clock blocks that made up the arm clock can be removed.
>> >>
>> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >> ---
>> >>  .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
>> >>  drivers/clk/samsung/clk-exynos4.c                  |   11
>> >> +++++------ drivers/clk/samsung/clk-exynos5250.c
>> >> |    8 ++++---- include/dt-bindings/clock/exynos5250.h
>> >> |    1 + 4 files changed, 11 insertions(+), 10 deletions(-)
>> >>
>> >> diff --git
>> >> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>> >> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>> >> index 99eae9c..acf867a 100644 ---
>> >> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt +++
>> >> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt @@
>> >> -38,6 +38,7 @@ clock which they consume.
>> >> ---------------------------- fin_pll            1
>> >> +  armclk             12
>> >>
>> >>    [Clock Gate for Special Clocks]
>> >>
>> >> diff --git a/drivers/clk/samsung/clk-exynos4.c
>> >> b/drivers/clk/samsung/clk-exynos4.c index 010f071..efcf4a3 100644
>> >> --- a/drivers/clk/samsung/clk-exynos4.c
>> >> +++ b/drivers/clk/samsung/clk-exynos4.c
>> >> @@ -437,8 +437,6 @@ static struct samsung_mux_clock
>> >> exynos4x12_mux_clks[] __initdata = {
>> >>  /* list of divider clocks supported in all exynos4 soc's */
>> >>  static struct samsung_div_clock exynos4_div_clks[] __initdata = {
>> >> -     DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3),
>> >> -     DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3),
>> >>       DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
>> >>       DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
>> >>       DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
>> >> @@ -484,8 +482,8 @@ static struct samsung_div_clock
>> >> exynos4_div_clks[] __initdata = { DIV(0, "div_spi_pre2",
>> >> "div_spi2", DIV_PERIL2, 8, 8), DIV(0, "div_audio1", "mout_audio1",
>> >> DIV_PERIL4, 0, 4), DIV(0, "div_audio2", "mout_audio2", DIV_PERIL4,
>> >> 16, 4),
>> >> -     DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
>> >> -     DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
>> >> 3),
>> >> +     DIV_F(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
>> >> 3,
>> >> +                     CLK_GET_RATE_NOCACHE, 0),
>> >>       DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
>> >>                       CLK_SET_RATE_PARENT, 0),
>> >>       DIV_F(0, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
>> >> @@ -870,7 +868,6 @@ static struct samsung_gate_clock
>> >> exynos4x12_gate_clks[] __initdata = {
>> >>  static struct samsung_clock_alias exynos4_aliases[] __initdata = {
>> >>       ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
>> >> -     ALIAS(CLK_ARM_CLK, NULL, "armclk"),
>> >>       ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"),
>> >>  };
>> >>
>> >> @@ -1125,12 +1122,14 @@ static void __init exynos4_clk_init(struct
>> >> device_node *np, samsung_clk_register_alias(exynos4_aliases,
>> >>                       ARRAY_SIZE(exynos4_aliases));
>> >>
>> >> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
>> >> reg_base); +
>> >
>> > I've got some doubts about allowing only the "mout_apll" clock to
>> > be the only parent for armclk Samsung clock.
>> >
>> > For the Exynos4412 it is also valid to have SCLK_MPLL_USER_C [*] as
>> > a parent for this clock.
>> >
>> > The problem is that you are reparenting the armclk to [*] with the
>> > register modification - no CCF involved.
>>
>> The MUX_CORE mux is part of the larger cpu clock type and not
>> registered as a separate mux clock with CCF. So I would like to know
>> if there are any potential issues you see if this mux clock is
>> internally managed within the set_rate of the larger cpu clock type.
>
> So the large opaque clock (armclk) starts with inputs to MUX_CORE (and
> embrace this MUX as well)?

Yes, the MUX_CORE is now part of the large opaque clock and will only
use mout_apll as the parent clock. The other parent will be used
temporarily only when the frequency of the mout_apll (leading to APLL)
has to be changed.

>
> If yes, then I don't mind if it is solely managed inside the armclk.
>
> This however allows the armclk to be fed from mout_apll[*] and
> sclk_mpll__user_c[**]. And this would be nice if reflected in the code.

Okay.

>
>>
>> >
>> > I just would like to know if this is yours design decision or
>> > something, that we have overlooked in the v1 of this patch series.
>>
>> I did overlook this one. This will be fixed in the next version by
>> ensuring that the dividers for SCLK_HPM clock will be updated only if
>> mout_apll is the parent of the MUX_HPM clock mux.
>
> Shall not they be updated if whatever connected to the MUX_HPM
> ([*] and [**]) changes?

They will be updated if their parent is mout_apll. If their parent is
a MPLL sourced clock, the divider will not be updated since the set
rate on this opaque clock will not change the frequency of the MPLL
sourced clock.

Thanks,
Thomas.

>
>>
>> Thanks,
>> Thomas.
>>
>> >
>> >>       pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
>> >>               "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk =
>> >> %ld\n", exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
>> >>               _get_rate("sclk_apll"),
>> >> _get_rate("sclk_mpll"), _get_rate("sclk_epll"),
>> >> _get_rate("sclk_vpll"),
>> >> -             _get_rate("arm_clk"));
>> >> +             _get_rate("armclk"));
>> >>  }
>> >>
>> >>
>> >> diff --git a/drivers/clk/samsung/clk-exynos5250.c
>> >> b/drivers/clk/samsung/clk-exynos5250.c index ff4beeb..487be36
>> >> 100644 --- a/drivers/clk/samsung/clk-exynos5250.c
>> >> +++ b/drivers/clk/samsung/clk-exynos5250.c
>> >> @@ -298,9 +298,8 @@ static struct samsung_div_clock
>> >> exynos5250_div_clks[] __initdata = { /*
>> >>        * CMU_CPU
>> >>        */
>> >> -     DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
>> >> -     DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
>> >> -     DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3, "armclk"),
>> >> +     DIV_F(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
>> >> +                     CLK_GET_RATE_NOCACHE, 0),
>> >>
>> >>       /*
>> >>        * CMU_TOP
>> >> @@ -684,8 +683,9 @@ static void __init exynos5250_clk_init(struct
>> >> device_node *np) ARRAY_SIZE(exynos5250_div_clks));
>> >>       samsung_clk_register_gate(exynos5250_gate_clks,
>> >>                       ARRAY_SIZE(exynos5250_gate_clks));
>> >> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
>> >> reg_base);
>> >>       pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
>> >> -                     _get_rate("div_arm2"));
>> >> +                     _get_rate("armclk"));
>> >>  }
>> >>  CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock",
>> >> exynos5250_clk_init); diff --git
>> >> a/include/dt-bindings/clock/exynos5250.h
>> >> b/include/dt-bindings/clock/exynos5250.h index 922f2dc..59a10fb
>> >> 100644 --- a/include/dt-bindings/clock/exynos5250.h +++
>> >> b/include/dt-bindings/clock/exynos5250.h @@ -21,6 +21,7 @@
>> >>  #define CLK_FOUT_CPLL                6
>> >>  #define CLK_FOUT_EPLL                7
>> >>  #define CLK_FOUT_VPLL                8
>> >> +#define CLK_ARM_CLK          12
>> >>
>> >>  /* gate for special clocks (sclk) */
>> >>  #define CLK_SCLK_CAM_BAYER   128
>> >
>> >
>> >
>> > --
>> > Best regards,
>> >
>> > Lukasz Majewski
>> >
>> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-01-21 11:15         ` Thomas Abraham
@ 2014-01-21 11:42           ` Lukasz Majewski
  0 siblings, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-21 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> Hi Lukasz,
> 
> On Tue, Jan 21, 2014 at 4:08 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> >> On Mon, Jan 20, 2014 at 1:17 PM, Lukasz Majewski
> >> <l.majewski@samsung.com> wrote:
> >> > Hi Thomas,
> >> >
> >> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >> >>
> >> >> With the addition of the new Samsung specific cpu-clock type,
> >> >> the arm clock can be represented as a cpu-clock type and the
> >> >> independent clock blocks that made up the arm clock can be
> >> >> removed.
> >> >>
> >> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> >> ---
> >> >>  .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
> >> >>  drivers/clk/samsung/clk-exynos4.c                  |   11
> >> >> +++++------ drivers/clk/samsung/clk-exynos5250.c
> >> >> |    8 ++++---- include/dt-bindings/clock/exynos5250.h
> >> >> |    1 + 4 files changed, 11 insertions(+), 10 deletions(-)
> >> >>
> >> >> diff --git
> >> >> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> >> >> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> >> >> index 99eae9c..acf867a 100644 ---
> >> >> a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> >> >> +++
> >> >> b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
> >> >> @@ -38,6 +38,7 @@ clock which they consume.
> >> >> ---------------------------- fin_pll            1
> >> >> +  armclk             12
> >> >>
> >> >>    [Clock Gate for Special Clocks]
> >> >>
> >> >> diff --git a/drivers/clk/samsung/clk-exynos4.c
> >> >> b/drivers/clk/samsung/clk-exynos4.c index 010f071..efcf4a3
> >> >> 100644 --- a/drivers/clk/samsung/clk-exynos4.c
> >> >> +++ b/drivers/clk/samsung/clk-exynos4.c
> >> >> @@ -437,8 +437,6 @@ static struct samsung_mux_clock
> >> >> exynos4x12_mux_clks[] __initdata = {
> >> >>  /* list of divider clocks supported in all exynos4 soc's */
> >> >>  static struct samsung_div_clock exynos4_div_clks[] __initdata
> >> >> = {
> >> >> -     DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3),
> >> >> -     DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3),
> >> >>       DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
> >> >>       DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
> >> >>       DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
> >> >> @@ -484,8 +482,8 @@ static struct samsung_div_clock
> >> >> exynos4_div_clks[] __initdata = { DIV(0, "div_spi_pre2",
> >> >> "div_spi2", DIV_PERIL2, 8, 8), DIV(0, "div_audio1",
> >> >> "mout_audio1", DIV_PERIL4, 0, 4), DIV(0, "div_audio2",
> >> >> "mout_audio2", DIV_PERIL4, 16, 4),
> >> >> -     DIV(CLK_ARM_CLK, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
> >> >> -     DIV(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0, 24,
> >> >> 3),
> >> >> +     DIV_F(CLK_SCLK_APLL, "sclk_apll", "mout_apll", DIV_CPU0,
> >> >> 24, 3,
> >> >> +                     CLK_GET_RATE_NOCACHE, 0),
> >> >>       DIV_F(0, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
> >> >>                       CLK_SET_RATE_PARENT, 0),
> >> >>       DIV_F(0, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
> >> >> @@ -870,7 +868,6 @@ static struct samsung_gate_clock
> >> >> exynos4x12_gate_clks[] __initdata = {
> >> >>  static struct samsung_clock_alias exynos4_aliases[] __initdata
> >> >> = { ALIAS(CLK_MOUT_CORE, NULL, "moutcore"),
> >> >> -     ALIAS(CLK_ARM_CLK, NULL, "armclk"),
> >> >>       ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"),
> >> >>  };
> >> >>
> >> >> @@ -1125,12 +1122,14 @@ static void __init
> >> >> exynos4_clk_init(struct device_node *np,
> >> >> samsung_clk_register_alias(exynos4_aliases,
> >> >> ARRAY_SIZE(exynos4_aliases));
> >> >>
> >> >> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
> >> >> reg_base); +
> >> >
> >> > I've got some doubts about allowing only the "mout_apll" clock to
> >> > be the only parent for armclk Samsung clock.
> >> >
> >> > For the Exynos4412 it is also valid to have SCLK_MPLL_USER_C [*]
> >> > as a parent for this clock.
> >> >
> >> > The problem is that you are reparenting the armclk to [*] with
> >> > the register modification - no CCF involved.
> >>
> >> The MUX_CORE mux is part of the larger cpu clock type and not
> >> registered as a separate mux clock with CCF. So I would like to
> >> know if there are any potential issues you see if this mux clock is
> >> internally managed within the set_rate of the larger cpu clock
> >> type.
> >
> > So the large opaque clock (armclk) starts with inputs to MUX_CORE
> > (and embrace this MUX as well)?
> 
> Yes, the MUX_CORE is now part of the large opaque clock and will only
> use mout_apll as the parent clock. The other parent will be used
> temporarily only when the frequency of the mout_apll (leading to APLL)
> has to be changed.
> 
> >
> > If yes, then I don't mind if it is solely managed inside the armclk.
> >
> > This however allows the armclk to be fed from mout_apll[*] and
> > sclk_mpll__user_c[**]. And this would be nice if reflected in the
> > code.
> 
> Okay.
> 
> >
> >>
> >> >
> >> > I just would like to know if this is yours design decision or
> >> > something, that we have overlooked in the v1 of this patch
> >> > series.
> >>
> >> I did overlook this one. This will be fixed in the next version by
> >> ensuring that the dividers for SCLK_HPM clock will be updated only
> >> if mout_apll is the parent of the MUX_HPM clock mux.
> >
> > Shall not they be updated if whatever connected to the MUX_HPM
> > ([*] and [**]) changes?
> 
> They will be updated if their parent is mout_apll. If their parent is
> a MPLL sourced clock, the divider will not be updated since the set
> rate on this opaque clock will not change the frequency of the MPLL
> sourced clock.

Ok, Thanks for clarification.

> 
> Thanks,
> Thomas.
> 
> >
> >>
> >> Thanks,
> >> Thomas.
> >>
> >> >
> >> >>       pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
> >> >>               "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk =
> >> >> %ld\n", exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
> >> >>               _get_rate("sclk_apll"),
> >> >> _get_rate("sclk_mpll"), _get_rate("sclk_epll"),
> >> >> _get_rate("sclk_vpll"),
> >> >> -             _get_rate("arm_clk"));
> >> >> +             _get_rate("armclk"));
> >> >>  }
> >> >>
> >> >>
> >> >> diff --git a/drivers/clk/samsung/clk-exynos5250.c
> >> >> b/drivers/clk/samsung/clk-exynos5250.c index ff4beeb..487be36
> >> >> 100644 --- a/drivers/clk/samsung/clk-exynos5250.c
> >> >> +++ b/drivers/clk/samsung/clk-exynos5250.c
> >> >> @@ -298,9 +298,8 @@ static struct samsung_div_clock
> >> >> exynos5250_div_clks[] __initdata = { /*
> >> >>        * CMU_CPU
> >> >>        */
> >> >> -     DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
> >> >> -     DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
> >> >> -     DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3,
> >> >> "armclk"),
> >> >> +     DIV_F(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3,
> >> >> +                     CLK_GET_RATE_NOCACHE, 0),
> >> >>
> >> >>       /*
> >> >>        * CMU_TOP
> >> >> @@ -684,8 +683,9 @@ static void __init
> >> >> exynos5250_clk_init(struct device_node *np)
> >> >> ARRAY_SIZE(exynos5250_div_clks));
> >> >> samsung_clk_register_gate(exynos5250_gate_clks,
> >> >> ARRAY_SIZE(exynos5250_gate_clks));
> >> >> +     samsung_register_arm_clock(np, CLK_ARM_CLK, "mout_apll",
> >> >> reg_base);
> >> >>       pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
> >> >> -                     _get_rate("div_arm2"));
> >> >> +                     _get_rate("armclk"));
> >> >>  }
> >> >>  CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock",
> >> >> exynos5250_clk_init); diff --git
> >> >> a/include/dt-bindings/clock/exynos5250.h
> >> >> b/include/dt-bindings/clock/exynos5250.h index 922f2dc..59a10fb
> >> >> 100644 --- a/include/dt-bindings/clock/exynos5250.h +++
> >> >> b/include/dt-bindings/clock/exynos5250.h @@ -21,6 +21,7 @@
> >> >>  #define CLK_FOUT_CPLL                6
> >> >>  #define CLK_FOUT_EPLL                7
> >> >>  #define CLK_FOUT_VPLL                8
> >> >> +#define CLK_ARM_CLK          12
> >> >>
> >> >>  /* gate for special clocks (sclk) */
> >> >>  #define CLK_SCLK_CAM_BAYER   128
> >> >
> >> >
> >> >
> >> > --
> >> > Best regards,
> >> >
> >> > Lukasz Majewski
> >> >
> >> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> >>
> >> _______________________________________________
> >> linux-arm-kernel mailing list
> >> linux-arm-kernel at lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5
  2014-01-21  7:31     ` Thomas Abraham
@ 2014-01-24 15:24       ` Thomas Abraham
  0 siblings, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-24 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Tue, Jan 21, 2014 at 1:01 PM, Thomas Abraham <ta.omasab@gmail.com> wrote:
> Hi Rob,
>
>
> On Sat, Jan 18, 2014 at 8:52 PM, Rob Herring <robherring2@gmail.com> wrote:
>> On Sat, Jan 18, 2014 at 6:10 AM, Thomas Abraham <ta.omasab@gmail.com> wrote:
>>> From: Thomas Abraham <thomas.ab@samsung.com>
>>>
>>> The clk ops of the new Samsung cpu clock provider type requires configuration
>>> data that will be programmed in the multiple clock blocks encapsulated within
>>> the cpu clock provider type. This configuration data is held in the clock
>>> controller node. Update clock binding documentation about this configuration
>>> data format for Samsung Exynos4 and Exynos5 platforms.
>>>
>>> Cc: Rob Herring <robh+dt@kernel.org>
>>
>> Please copy all maintainers.
>
> Okay.
>
>>
>>> Cc: Tomasz Figa <t.figa@samsung.com>
>>> Cc: <devicetree@vger.kernel.org>
>>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>>> ---
>>>  .../devicetree/bindings/clock/exynos4-clock.txt    |   30 ++++++++++++++++++++
>>>  .../devicetree/bindings/clock/exynos5250-clock.txt |   21 ++++++++++++++
>>>  2 files changed, 51 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
>>> index a2ac2d9..c28aabd 100644
>>> --- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
>>> +++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
>>> @@ -15,6 +15,29 @@ Required Properties:
>>>
>>>  - #clock-cells: should be 1.
>>>
>>> +- arm-frequency-table: defines the list of arm clock speeds supported and
>>
>> Seems like a Samsung specific property and nothing to do with ARM, so
>> it should be named accordingly.
>
> Okay.
>
>>
>>> +  the associated configuration values required to setup the clock controller
>>> +  for generating those speeds. The format of each entry included in the
>>> +  arm-frequency-table should be as defined below (#cells per entry = 13)
>>> +
>>> +  - for Exynos4210 and Exynos4212 based platforms:
>>> +      cell #1: arm clock frequency
>>> +      cell #2: expected arm clock parent frequency
>>> +      cell #3 ~ cell 12#: value of clock divider in the following order
>>> +              core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
>>> +              atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
>>> +              copy_ratio, hpm_ratio.
>>> +      cell #13: reserved (should be zero).
>>> +
>>> +  - for Exynos4412 based platforms:
>>> +      cell #1: arm clock frequency
>>> +      cell #2: expected arm clock parent frequency
>>> +      cell #3 ~ cell #13: value of clock divider in the following order
>>> +              core_ratio, corem0_ratio, corem1_ratio, periph_ratio,
>>> +              atb_ratio, pclk_dbg_ratio, apll_ratio, core2_ratio,
>>> +              copy_ratio, hpm_ratio, cores_ratio
>>
>> You don't need voltages? Are the h/w limitations really ratios or each
>> clock has a max frequency that must be maintained? I would expect the
>> latter and think it would be better to specify maximum frequencies of
>> each clock. Then you can calculate the dividers to keep frequencies in
>> range.
>
> Voltage is not needed here since the cpu clock speed is managed by the
> cpufreq driver which will take care of setting appropriate voltage.
> Any other users apart from cpufreq will have to setup the voltage
> appropriately.
>
> About the ratios, yes the user manual lists the optimal clock
> frequency for these clocks. As suggested, I will remove the ratio list
> for these clocks.

I tried the approach of listing the optimal frequencies of these
clocks in dt and then calculating a divider value. But it turns out
that the divider values for these clocks is dependent on the frequency
of the PLL from which they are derived (or the voltage applied to the
CPU clock domain). During tests, the system is unstable if divider
values are calculated using the optimal clock speed listed in the SoC
manual.

So the list of divider values as used in this series (and documented
above) is required. Can I continue to use the binding as documented
above?

Thanks,
Thomas.

>
>>
>> How will this scale to multi-cluster chips with different frequency ranges?
>
> Usually, each cluster would have its own independent clock input. So
> there will be two or more cpu clocks in multi-cluster chips. So the
> clocks can be independently programmed as required by the cluster.
>
>>
>> Rob
>>
>
> Thanks Rob for your review.
>
> Thomas.
>
>>> +
>>> +
>>>  The following is the list of clocks generated by the controller. Each clock is
>>>  assigned an identifier and client nodes use this identifier to specify the
>>>  clock which they consume. Some of the clocks are available only on a particular
>>> @@ -275,6 +298,13 @@ Example 1: An example of a clock controller node is listed below.
>>>                 compatible = "samsung,exynos4210-clock";
>>>                 reg = <0x10030000 0x20000>;
>>>                 #clock-cells = <1>;
>>> +
>>> +               arm-frequency-table = <1200000 1200000 0 3 7 3 4 1 7 0 5 0>,
>>> +                                     <1000000 1000000 0 3 7 3 4 1 7 0 4 0>,
>>> +                                     < 800000  800000 0 3 7 3 3 1 7 0 3 0>,
>>> +                                     < 500000  500000 0 3 7 3 3 1 7 0 3 0>,
>>> +                                     < 400000  400000 0 3 7 3 3 1 7 0 3 0>,
>>> +                                     < 200000  200000 0 1 3 1 1 1 0 0 3 0>;
>>>         };
>>>
>>>  Example 2: UART controller node that consumes the clock generated by the clock
>>> diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>>> index 72ce617..99eae9c 100644
>>> --- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>>> +++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
>>> @@ -13,6 +13,20 @@ Required Properties:
>>>
>>>  - #clock-cells: should be 1.
>>>
>>> +- arm-frequency-table: defines the list of arm clock speeds supported and
>>> +  the associated configuration values required to setup the clock controller
>>> +  for generating those speeds. The format of each entry included in the
>>> +  arm-frequency-table should be as defined below (#cells per entry = 13)
>>> +
>>> +      cell #1: arm clock frequency
>>> +      cell #2: expected arm clock parent frequency
>>> +      cell #3 ~ cell #12: value of clock divider in the following order
>>> +              arm_ratio, cpud_ratio, acp_ratio, periph_ratio,
>>> +              atb_ratio, pclk_dbg_ratio, apll_ratio, arm2_ratio,
>>> +              copy_ratio, hpm_ratio
>>> +      cell #13: reserved (should be zero)
>>> +
>>> +
>>>  The following is the list of clocks generated by the controller. Each clock is
>>>  assigned an identifier and client nodes use this identifier to specify the
>>>  clock which they consume.
>>> @@ -177,6 +191,13 @@ Example 1: An example of a clock controller node is listed below.
>>>                 compatible = "samsung,exynos5250-clock";
>>>                 reg = <0x10010000 0x30000>;
>>>                 #clock-cells = <1>;
>>> +
>>> +               arm-frequency-table = <1700000 1700000 0 3 7 7 7 3 5 0 0 2>,
>>> +                                     <1600000 1600000 0 3 7 7 7 1 4 0 0 2>,
>>> +                                     <1500000 1500000 0 2 7 7 7 1 4 0 0 2>,
>>> +                                     <1400000 1400000 0 2 7 7 6 1 4 0 0 2>,
>>> +                                     <1300000 1300000 0 2 7 7 6 1 3 0 0 2>,
>>> +                                     <1200000 1200000 0 2 7 7 5 1 3 0 0 2>;
>>>         };
>>>
>>>  Example 2: UART controller node that consumes the clock generated by the clock
>>> --
>>> 1.6.6.rc2
>>>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
  2014-01-20  8:09   ` Lukasz Majewski
@ 2014-01-27  7:16   ` Shawn Guo
  2014-01-28  4:30     ` Thomas Abraham
  2014-01-27 20:25   ` Mike Turquette
  2 siblings, 1 reply; 51+ messages in thread
From: Shawn Guo @ 2014-01-27  7:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jan 18, 2014 at 05:40:51PM +0530, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> On some platforms such as the Samsung Exynos, changing the frequency
> of the CPU clock requires changing the frequency of the PLL that is
> supplying the CPU clock. To change the frequency of the PLL, the CPU
> clock is temporarily reparented to another parent clock.
> 
> The clock frequency of this temporary parent clock could be much higher
> than the clock frequency of the PLL at the time of reparenting. Due
> to the temporary increase in the CPU clock speed, the CPU (and any other
> components in the CPU clock domain such as dividers, mux, etc.) have to
> to be operated at a higher voltage level, called the safe voltage level.
> This patch adds optional support to temporarily switch to a safe voltage
> level during CPU frequency transitions.
> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++

The devicetree list should be copied for this change.

>  drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
>  2 files changed, 40 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> index f055515..37453ab 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> @@ -19,6 +19,12 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
> +- safe-opp: Certain platforms require that during a opp transition,
> +  a system should not go below a particular opp level. For such systems,
> +  this property specifies the minimum opp to be maintained during the
> +  opp transitions. The safe-opp value is a tuple with first element
> +  representing the safe frequency and the second element representing the
> +  safe voltage.
>  
>  Examples:
>  
> @@ -36,6 +42,7 @@ cpus {
>  			396000  950000
>  			198000  850000
>  		>;
> +		safe-opp = <396000 950000>
>  		clock-latency = <61036>; /* two CLK32 periods */
>  		#cooling-cells = <2>;
>  		cooling-min-level = <0>;
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index 0c12ffc..075d3d1 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -27,6 +27,8 @@
>  
>  static unsigned int transition_latency;
>  static unsigned int voltage_tolerance; /* in percentage */
> +static unsigned long safe_frequency;
> +static unsigned long safe_voltage;
>  
>  static struct device *cpu_dev;
>  static struct clk *cpu_clk;
> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>  		volt_old = regulator_get_voltage(cpu_reg);
>  	}
>  
> -	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> +	pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",

This is an unnecessary change?

Otherwise,

Acked-by: Shawn Guo <shawn.guo@linaro.org>

Shawn

>  		 old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>  		 new_freq / 1000, volt ? volt / 1000 : -1);
>  
>  	/* scaling up?  scale voltage before frequency */
> -	if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> +	if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> +				new_freq >= safe_frequency) {
>  		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>  		if (ret) {
>  			pr_err("failed to scale voltage up: %d\n", ret);
>  			return ret;
>  		}
> +	} else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
> +		/*
> +		 * the scaled up voltage level for the new_freq is lower
> +		 * than the safe voltage level. so set safe_voltage
> +		 * as the intermediate voltage level and revert it
> +		 * back after the frequency has been changed.
> +		 */
> +		ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
> +		if (ret) {
> +			pr_err("failed to set safe voltage: %d\n", ret);
> +			return ret;
> +		}
>  	}
>  
>  	ret = clk_set_rate(cpu_clk, freq_exact);
> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>  	}
>  
>  	/* scaling down?  scale voltage after frequency */
> -	if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> +	if (!IS_ERR(cpu_reg) &&
> +			(new_freq < old_freq || new_freq < safe_frequency)) {
>  		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>  		if (ret) {
>  			pr_err("failed to scale voltage down: %d\n", ret);
> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>  
>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>  {
> +	const struct property *prop;
> +	struct dev_pm_opp *opp;
>  	struct device_node *np;
>  	int ret;
>  
> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>  		goto out_put_node;
>  	}
>  
> +	prop = of_find_property(np, "safe-opp", NULL);
> +	if (prop) {
> +		if (prop->value && (prop->length / sizeof(u32)) == 2) {
> +			const __be32 *val;
> +			val = prop->value;
> +			safe_frequency = be32_to_cpup(val++);
> +			safe_voltage = be32_to_cpup(val);
> +		} else {
> +			pr_err("invalid safe-opp level specified\n");
> +		}
> +	}
> +
>  	of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>  
>  	if (of_property_read_u32(np, "clock-latency", &transition_latency))
>  		transition_latency = CPUFREQ_ETERNAL;
>  
>  	if (!IS_ERR(cpu_reg)) {
> -		struct dev_pm_opp *opp;
>  		unsigned long min_uV, max_uV;
>  		int i;
>  
> -- 
> 1.6.6.rc2
> 

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
  2014-01-20  8:09   ` Lukasz Majewski
  2014-01-27  7:16   ` Shawn Guo
@ 2014-01-27 20:25   ` Mike Turquette
  2014-01-28  5:30     ` Thomas Abraham
  2 siblings, 1 reply; 51+ messages in thread
From: Mike Turquette @ 2014-01-27 20:25 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Thomas Abraham (2014-01-18 04:10:51)
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> On some platforms such as the Samsung Exynos, changing the frequency
> of the CPU clock requires changing the frequency of the PLL that is
> supplying the CPU clock. To change the frequency of the PLL, the CPU
> clock is temporarily reparented to another parent clock.
> 
> The clock frequency of this temporary parent clock could be much higher
> than the clock frequency of the PLL at the time of reparenting. Due
> to the temporary increase in the CPU clock speed, the CPU (and any other
> components in the CPU clock domain such as dividers, mux, etc.) have to
> to be operated at a higher voltage level, called the safe voltage level.
> This patch adds optional support to temporarily switch to a safe voltage
> level during CPU frequency transitions.
> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>

I'm not a fan of this change. This corner case should be abstracted away
somehow. I had talked to Chander Kayshap previously about handling
voltage changes in clock notifier callbacks, which then renders any
voltage change as a trivial part of the clock rate transition. That
means that this "safe voltage" thing could be handled automagically
without any additional code in the CPUfreq driver.

There are two nice ways to do this with the clock framework. First is
explicit re-parenting with voltage scaling done in the clock rate-change
notifiers:

clk_set_parent(cpu_clk, temp_parent);
/* implicit voltage scaling to "safe voltage" happens above */
clk_set_rate(pll, some_rate);
clk_set_parent(cpu_clk, pll);
/* implicit voltage scaling to nominal OPP voltage happens above */

The above sequence would require a separate exnyos CPUfreq driver, due
to the added clk_set_parent logic.

The second way to do this is to abstract the clk re-muxing logic out
into the clk driver, which would allow cpufreq-cpu0 to be used for the
exynos chips.

I'm more a fan of explicitly listing the Exact Steps for the cpu opp
transition in a separate exynos-specific CPUfreq driver, but that's
probably an unpopular view.

Regards,
Mike

> ---
>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>  drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
>  2 files changed, 40 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> index f055515..37453ab 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> @@ -19,6 +19,12 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
> +- safe-opp: Certain platforms require that during a opp transition,
> +  a system should not go below a particular opp level. For such systems,
> +  this property specifies the minimum opp to be maintained during the
> +  opp transitions. The safe-opp value is a tuple with first element
> +  representing the safe frequency and the second element representing the
> +  safe voltage.
>  
>  Examples:
>  
> @@ -36,6 +42,7 @@ cpus {
>                         396000  950000
>                         198000  850000
>                 >;
> +               safe-opp = <396000 950000>
>                 clock-latency = <61036>; /* two CLK32 periods */
>                 #cooling-cells = <2>;
>                 cooling-min-level = <0>;
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index 0c12ffc..075d3d1 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -27,6 +27,8 @@
>  
>  static unsigned int transition_latency;
>  static unsigned int voltage_tolerance; /* in percentage */
> +static unsigned long safe_frequency;
> +static unsigned long safe_voltage;
>  
>  static struct device *cpu_dev;
>  static struct clk *cpu_clk;
> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>                 volt_old = regulator_get_voltage(cpu_reg);
>         }
>  
> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>                  new_freq / 1000, volt ? volt / 1000 : -1);
>  
>         /* scaling up?  scale voltage before frequency */
> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> +                               new_freq >= safe_frequency) {
>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>                 if (ret) {
>                         pr_err("failed to scale voltage up: %d\n", ret);
>                         return ret;
>                 }
> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
> +               /*
> +                * the scaled up voltage level for the new_freq is lower
> +                * than the safe voltage level. so set safe_voltage
> +                * as the intermediate voltage level and revert it
> +                * back after the frequency has been changed.
> +                */
> +               ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
> +               if (ret) {
> +                       pr_err("failed to set safe voltage: %d\n", ret);
> +                       return ret;
> +               }
>         }
>  
>         ret = clk_set_rate(cpu_clk, freq_exact);
> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>         }
>  
>         /* scaling down?  scale voltage after frequency */
> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> +       if (!IS_ERR(cpu_reg) &&
> +                       (new_freq < old_freq || new_freq < safe_frequency)) {
>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>                 if (ret) {
>                         pr_err("failed to scale voltage down: %d\n", ret);
> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>  
>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>  {
> +       const struct property *prop;
> +       struct dev_pm_opp *opp;
>         struct device_node *np;
>         int ret;
>  
> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>                 goto out_put_node;
>         }
>  
> +       prop = of_find_property(np, "safe-opp", NULL);
> +       if (prop) {
> +               if (prop->value && (prop->length / sizeof(u32)) == 2) {
> +                       const __be32 *val;
> +                       val = prop->value;
> +                       safe_frequency = be32_to_cpup(val++);
> +                       safe_voltage = be32_to_cpup(val);
> +               } else {
> +                       pr_err("invalid safe-opp level specified\n");
> +               }
> +       }
> +
>         of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>  
>         if (of_property_read_u32(np, "clock-latency", &transition_latency))
>                 transition_latency = CPUFREQ_ETERNAL;
>  
>         if (!IS_ERR(cpu_reg)) {
> -               struct dev_pm_opp *opp;
>                 unsigned long min_uV, max_uV;
>                 int i;
>  
> -- 
> 1.6.6.rc2
> 

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-27  7:16   ` Shawn Guo
@ 2014-01-28  4:30     ` Thomas Abraham
  0 siblings, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-28  4:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Shawn,

On Mon, Jan 27, 2014 at 12:46 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Sat, Jan 18, 2014 at 05:40:51PM +0530, Thomas Abraham wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> On some platforms such as the Samsung Exynos, changing the frequency
>> of the CPU clock requires changing the frequency of the PLL that is
>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>> clock is temporarily reparented to another parent clock.
>>
>> The clock frequency of this temporary parent clock could be much higher
>> than the clock frequency of the PLL at the time of reparenting. Due
>> to the temporary increase in the CPU clock speed, the CPU (and any other
>> components in the CPU clock domain such as dividers, mux, etc.) have to
>> to be operated at a higher voltage level, called the safe voltage level.
>> This patch adds optional support to temporarily switch to a safe voltage
>> level during CPU frequency transitions.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>
> The devicetree list should be copied for this change.

Okay, will do in the next version.

>
>>  drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
>>  2 files changed, 40 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..37453ab 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,12 @@ Optional properties:
>>  - cooling-min-level:
>>  - cooling-max-level:
>>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- safe-opp: Certain platforms require that during a opp transition,
>> +  a system should not go below a particular opp level. For such systems,
>> +  this property specifies the minimum opp to be maintained during the
>> +  opp transitions. The safe-opp value is a tuple with first element
>> +  representing the safe frequency and the second element representing the
>> +  safe voltage.
>>
>>  Examples:
>>
>> @@ -36,6 +42,7 @@ cpus {
>>                       396000  950000
>>                       198000  850000
>>               >;
>> +             safe-opp = <396000 950000>
>>               clock-latency = <61036>; /* two CLK32 periods */
>>               #cooling-cells = <2>;
>>               cooling-min-level = <0>;
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..075d3d1 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -27,6 +27,8 @@
>>
>>  static unsigned int transition_latency;
>>  static unsigned int voltage_tolerance; /* in percentage */
>> +static unsigned long safe_frequency;
>> +static unsigned long safe_voltage;
>>
>>  static struct device *cpu_dev;
>>  static struct clk *cpu_clk;
>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>               volt_old = regulator_get_voltage(cpu_reg);
>>       }
>>
>> -     pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> +     pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>
> This is an unnecessary change?

Yes, sorry missed that.

>
> Otherwise,
>
> Acked-by: Shawn Guo <shawn.guo@linaro.org>

Thanks for your review.

Regards,
Thomas.

>
> Shawn
>
>>                old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>>                new_freq / 1000, volt ? volt / 1000 : -1);
>>
>>       /* scaling up?  scale voltage before frequency */
>> -     if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>> +     if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>> +                             new_freq >= safe_frequency) {
>>               ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>               if (ret) {
>>                       pr_err("failed to scale voltage up: %d\n", ret);
>>                       return ret;
>>               }
>> +     } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>> +             /*
>> +              * the scaled up voltage level for the new_freq is lower
>> +              * than the safe voltage level. so set safe_voltage
>> +              * as the intermediate voltage level and revert it
>> +              * back after the frequency has been changed.
>> +              */
>> +             ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>> +             if (ret) {
>> +                     pr_err("failed to set safe voltage: %d\n", ret);
>> +                     return ret;
>> +             }
>>       }
>>
>>       ret = clk_set_rate(cpu_clk, freq_exact);
>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>       }
>>
>>       /* scaling down?  scale voltage after frequency */
>> -     if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>> +     if (!IS_ERR(cpu_reg) &&
>> +                     (new_freq < old_freq || new_freq < safe_frequency)) {
>>               ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>               if (ret) {
>>                       pr_err("failed to scale voltage down: %d\n", ret);
>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>
>>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>  {
>> +     const struct property *prop;
>> +     struct dev_pm_opp *opp;
>>       struct device_node *np;
>>       int ret;
>>
>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>               goto out_put_node;
>>       }
>>
>> +     prop = of_find_property(np, "safe-opp", NULL);
>> +     if (prop) {
>> +             if (prop->value && (prop->length / sizeof(u32)) == 2) {
>> +                     const __be32 *val;
>> +                     val = prop->value;
>> +                     safe_frequency = be32_to_cpup(val++);
>> +                     safe_voltage = be32_to_cpup(val);
>> +             } else {
>> +                     pr_err("invalid safe-opp level specified\n");
>> +             }
>> +     }
>> +
>>       of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>
>>       if (of_property_read_u32(np, "clock-latency", &transition_latency))
>>               transition_latency = CPUFREQ_ETERNAL;
>>
>>       if (!IS_ERR(cpu_reg)) {
>> -             struct dev_pm_opp *opp;
>>               unsigned long min_uV, max_uV;
>>               int i;
>>
>> --
>> 1.6.6.rc2
>>
>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-27 20:25   ` Mike Turquette
@ 2014-01-28  5:30     ` Thomas Abraham
  2014-01-28  8:17       ` Lukasz Majewski
                         ` (2 more replies)
  0 siblings, 3 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-28  5:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mike,

On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
> Quoting Thomas Abraham (2014-01-18 04:10:51)
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> On some platforms such as the Samsung Exynos, changing the frequency
>> of the CPU clock requires changing the frequency of the PLL that is
>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>> clock is temporarily reparented to another parent clock.
>>
>> The clock frequency of this temporary parent clock could be much higher
>> than the clock frequency of the PLL at the time of reparenting. Due
>> to the temporary increase in the CPU clock speed, the CPU (and any other
>> components in the CPU clock domain such as dividers, mux, etc.) have to
>> to be operated at a higher voltage level, called the safe voltage level.
>> This patch adds optional support to temporarily switch to a safe voltage
>> level during CPU frequency transitions.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>
> I'm not a fan of this change. This corner case should be abstracted away
> somehow. I had talked to Chander Kayshap previously about handling
> voltage changes in clock notifier callbacks, which then renders any
> voltage change as a trivial part of the clock rate transition. That
> means that this "safe voltage" thing could be handled automagically
> without any additional code in the CPUfreq driver.
>
> There are two nice ways to do this with the clock framework. First is
> explicit re-parenting with voltage scaling done in the clock rate-change
> notifiers:
>
> clk_set_parent(cpu_clk, temp_parent);
> /* implicit voltage scaling to "safe voltage" happens above */
> clk_set_rate(pll, some_rate);
> clk_set_parent(cpu_clk, pll);
> /* implicit voltage scaling to nominal OPP voltage happens above */
>
> The above sequence would require a separate exnyos CPUfreq driver, due
> to the added clk_set_parent logic.
>
> The second way to do this is to abstract the clk re-muxing logic out
> into the clk driver, which would allow cpufreq-cpu0 to be used for the
> exynos chips.

This is the approach this patch series takes (patch 2/7). The clock
re-muxing logic is handled by a clock driver code. The difference from
what you suggested is that the safe voltage (that may be optionally)
required before doing the re-muxing is handled here in cpufreq-cpu0
driver.

The safe voltage setup can be done in the notifier as you suggested.
But, doing that in cpufreq-cpu0 driver will help other platforms reuse
this feature if required. Also, if done here, the regulator handling
is localized in this driver which otherwise would need to be handled
in two places, cpufreq-cpu0 driver and the clock notifier.

So I tend to prefer the approach in this patch but I am willing to
consider any suggestions. Shawn, it would be helpful if you could let
us know your thoughts on this. I am almost done with testing the v3 of
this series and want to post it so if there are any objections to the
changes in this patch, please let me know.

Thanks,
Thomas.

>
> I'm more a fan of explicitly listing the Exact Steps for the cpu opp
> transition in a separate exynos-specific CPUfreq driver, but that's
> probably an unpopular view.
>
> Regards,
> Mike
>
>> ---
>>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>>  drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
>>  2 files changed, 40 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..37453ab 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,12 @@ Optional properties:
>>  - cooling-min-level:
>>  - cooling-max-level:
>>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- safe-opp: Certain platforms require that during a opp transition,
>> +  a system should not go below a particular opp level. For such systems,
>> +  this property specifies the minimum opp to be maintained during the
>> +  opp transitions. The safe-opp value is a tuple with first element
>> +  representing the safe frequency and the second element representing the
>> +  safe voltage.
>>
>>  Examples:
>>
>> @@ -36,6 +42,7 @@ cpus {
>>                         396000  950000
>>                         198000  850000
>>                 >;
>> +               safe-opp = <396000 950000>
>>                 clock-latency = <61036>; /* two CLK32 periods */
>>                 #cooling-cells = <2>;
>>                 cooling-min-level = <0>;
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..075d3d1 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -27,6 +27,8 @@
>>
>>  static unsigned int transition_latency;
>>  static unsigned int voltage_tolerance; /* in percentage */
>> +static unsigned long safe_frequency;
>> +static unsigned long safe_voltage;
>>
>>  static struct device *cpu_dev;
>>  static struct clk *cpu_clk;
>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>                 volt_old = regulator_get_voltage(cpu_reg);
>>         }
>>
>> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>>                  new_freq / 1000, volt ? volt / 1000 : -1);
>>
>>         /* scaling up?  scale voltage before frequency */
>> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>> +                               new_freq >= safe_frequency) {
>>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>                 if (ret) {
>>                         pr_err("failed to scale voltage up: %d\n", ret);
>>                         return ret;
>>                 }
>> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>> +               /*
>> +                * the scaled up voltage level for the new_freq is lower
>> +                * than the safe voltage level. so set safe_voltage
>> +                * as the intermediate voltage level and revert it
>> +                * back after the frequency has been changed.
>> +                */
>> +               ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>> +               if (ret) {
>> +                       pr_err("failed to set safe voltage: %d\n", ret);
>> +                       return ret;
>> +               }
>>         }
>>
>>         ret = clk_set_rate(cpu_clk, freq_exact);
>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>         }
>>
>>         /* scaling down?  scale voltage after frequency */
>> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>> +       if (!IS_ERR(cpu_reg) &&
>> +                       (new_freq < old_freq || new_freq < safe_frequency)) {
>>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>                 if (ret) {
>>                         pr_err("failed to scale voltage down: %d\n", ret);
>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>
>>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>  {
>> +       const struct property *prop;
>> +       struct dev_pm_opp *opp;
>>         struct device_node *np;
>>         int ret;
>>
>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>                 goto out_put_node;
>>         }
>>
>> +       prop = of_find_property(np, "safe-opp", NULL);
>> +       if (prop) {
>> +               if (prop->value && (prop->length / sizeof(u32)) == 2) {
>> +                       const __be32 *val;
>> +                       val = prop->value;
>> +                       safe_frequency = be32_to_cpup(val++);
>> +                       safe_voltage = be32_to_cpup(val);
>> +               } else {
>> +                       pr_err("invalid safe-opp level specified\n");
>> +               }
>> +       }
>> +
>>         of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>
>>         if (of_property_read_u32(np, "clock-latency", &transition_latency))
>>                 transition_latency = CPUFREQ_ETERNAL;
>>
>>         if (!IS_ERR(cpu_reg)) {
>> -               struct dev_pm_opp *opp;
>>                 unsigned long min_uV, max_uV;
>>                 int i;
>>
>> --
>> 1.6.6.rc2
>>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28  5:30     ` Thomas Abraham
@ 2014-01-28  8:17       ` Lukasz Majewski
  2014-01-28 11:36         ` Thomas Abraham
  2014-01-28 11:49       ` Shawn Guo
  2014-01-28 18:47       ` Mike Turquette
  2 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-28  8:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas, Mike

> Hi Mike,
> 
> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
> <mturquette@linaro.org> wrote:
> > Quoting Thomas Abraham (2014-01-18 04:10:51)
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> On some platforms such as the Samsung Exynos, changing the
> >> frequency of the CPU clock requires changing the frequency of the
> >> PLL that is supplying the CPU clock. To change the frequency of
> >> the PLL, the CPU clock is temporarily reparented to another parent
> >> clock.
> >>
> >> The clock frequency of this temporary parent clock could be much
> >> higher than the clock frequency of the PLL at the time of
> >> reparenting. Due to the temporary increase in the CPU clock speed,
> >> the CPU (and any other components in the CPU clock domain such as
> >> dividers, mux, etc.) have to to be operated at a higher voltage
> >> level, called the safe voltage level. This patch adds optional
> >> support to temporarily switch to a safe voltage level during CPU
> >> frequency transitions.
> >>
> >> Cc: Shawn Guo <shawn.guo@linaro.org>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >
> > I'm not a fan of this change. This corner case should be abstracted
> > away somehow. I had talked to Chander Kayshap previously about
> > handling voltage changes in clock notifier callbacks, which then
> > renders any voltage change as a trivial part of the clock rate
> > transition. That means that this "safe voltage" thing could be
> > handled automagically without any additional code in the CPUfreq
> > driver.
> >
> > There are two nice ways to do this with the clock framework. First
> > is explicit re-parenting with voltage scaling done in the clock
> > rate-change notifiers:
> >
> > clk_set_parent(cpu_clk, temp_parent);
> > /* implicit voltage scaling to "safe voltage" happens above */
> > clk_set_rate(pll, some_rate);
> > clk_set_parent(cpu_clk, pll);
> > /* implicit voltage scaling to nominal OPP voltage happens above */
> >

I must agree with Mike here. In my opinion the above approach is more
compliant with CCF (as I've pointed it out in my other comment - the
cpu_clk has more than one parent and we could switch between them when
needed). 

> > The above sequence would require a separate exnyos CPUfreq driver,
> > due to the added clk_set_parent logic.
> >
> > The second way to do this is to abstract the clk re-muxing logic out
> > into the clk driver, which would allow cpufreq-cpu0 to be used for
> > the exynos chips.
> 
> This is the approach this patch series takes (patch 2/7). The clock
> re-muxing logic is handled by a clock driver code. The difference from
> what you suggested is that the safe voltage (that may be optionally)
> required before doing the re-muxing is handled here in cpufreq-cpu0
> driver.
> 
> The safe voltage setup can be done in the notifier as you suggested.

If the clk_set_parent() approach is not suitable, then cannot we
consider using the one from highbank-cpufreq.c?

Here we have cpufreq-cpu0.c which sets voltage of the cpu_clk. 
In the highbank-cpufreq.c there are clock notifiers to change the
voltage.

Cannot Exynos reuse such approach? Why shall we pollute cpufreq-cpu0.c
with another solution?

> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
> this feature if required. Also, if done here, the regulator handling
> is localized in this driver which otherwise would need to be handled
> in two places, cpufreq-cpu0 driver and the clock notifier.

I think that there is a logical distinction between setting voltage for
cpufreq-cpu0 related clock and increasing voltage of reparented clock.

The former fits naturally to cpufreq-cpu0, when the latter seems like
some corner case (as Mike pointed out) for Exynos. 

> 
> So I tend to prefer the approach in this patch but I am willing to
> consider any suggestions. 

Thomas, what do you think about highbank-cpufreq.c approach (with
using clock notifiers)? 

Do you think, that it is feasible to reuse it with Exynos?

> Shawn, it would be helpful if you could let
> us know your thoughts on this. I am almost done with testing the v3 of
> this series and want to post it so if there are any objections to the
> changes in this patch, please let me know.
> 
> Thanks,
> Thomas.
> 
> >
> > I'm more a fan of explicitly listing the Exact Steps for the cpu opp
> > transition in a separate exynos-specific CPUfreq driver, but that's
> > probably an unpopular view.
> >
> > Regards,
> > Mike
> >
> >> ---
> >>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
> >>  drivers/cpufreq/cpufreq-cpu0.c                     |   37
> >> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4
> >> deletions(-)
> >>
> >> diff --git
> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
> >> f055515..37453ab 100644 ---
> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@
> >> -19,6 +19,12 @@ Optional properties:
> >>  - cooling-min-level:
> >>  - cooling-max-level:
> >>       Please refer to
> >> Documentation/devicetree/bindings/thermal/thermal.txt. +-
> >> safe-opp: Certain platforms require that during a opp transition,
> >> +  a system should not go below a particular opp level. For such
> >> systems,
> >> +  this property specifies the minimum opp to be maintained during
> >> the
> >> +  opp transitions. The safe-opp value is a tuple with first
> >> element
> >> +  representing the safe frequency and the second element
> >> representing the
> >> +  safe voltage.
> >>
> >>  Examples:
> >>
> >> @@ -36,6 +42,7 @@ cpus {
> >>                         396000  950000
> >>                         198000  850000
> >>                 >;
> >> +               safe-opp = <396000 950000>
> >>                 clock-latency = <61036>; /* two CLK32 periods */
> >>                 #cooling-cells = <2>;
> >>                 cooling-min-level = <0>;
> >> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> >> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
> >> --- a/drivers/cpufreq/cpufreq-cpu0.c
> >> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> >> @@ -27,6 +27,8 @@
> >>
> >>  static unsigned int transition_latency;
> >>  static unsigned int voltage_tolerance; /* in percentage */
> >> +static unsigned long safe_frequency;
> >> +static unsigned long safe_voltage;
> >>
> >>  static struct device *cpu_dev;
> >>  static struct clk *cpu_clk;
> >> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct
> >> cpufreq_policy *policy, unsigned int index) volt_old =
> >> regulator_get_voltage(cpu_reg); }
> >>
> >> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
> >>                  new_freq / 1000, volt ? volt / 1000 : -1);
> >>
> >>         /* scaling up?  scale voltage before frequency */
> >> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> >> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> >> +                               new_freq >= safe_frequency) {
> >>                 ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> tol); if (ret) {
> >>                         pr_err("failed to scale voltage up: %d\n",
> >> ret); return ret;
> >>                 }
> >> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
> >> +               /*
> >> +                * the scaled up voltage level for the new_freq is
> >> lower
> >> +                * than the safe voltage level. so set safe_voltage
> >> +                * as the intermediate voltage level and revert it
> >> +                * back after the frequency has been changed.
> >> +                */
> >> +               ret = regulator_set_voltage_tol(cpu_reg,
> >> safe_voltage, tol);
> >> +               if (ret) {
> >> +                       pr_err("failed to set safe voltage: %d\n",
> >> ret);
> >> +                       return ret;
> >> +               }
> >>         }
> >>
> >>         ret = clk_set_rate(cpu_clk, freq_exact);
> >> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct
> >> cpufreq_policy *policy, unsigned int index) }
> >>
> >>         /* scaling down?  scale voltage after frequency */
> >> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> >> +       if (!IS_ERR(cpu_reg) &&
> >> +                       (new_freq < old_freq || new_freq <
> >> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> tol); if (ret) {
> >>                         pr_err("failed to scale voltage down:
> >> %d\n", ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
> >> cpu0_cpufreq_driver = {
> >>
> >>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
> >>  {
> >> +       const struct property *prop;
> >> +       struct dev_pm_opp *opp;
> >>         struct device_node *np;
> >>         int ret;
> >>
> >> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
> >> platform_device *pdev) goto out_put_node;
> >>         }
> >>
> >> +       prop = of_find_property(np, "safe-opp", NULL);
> >> +       if (prop) {
> >> +               if (prop->value && (prop->length / sizeof(u32)) ==
> >> 2) {
> >> +                       const __be32 *val;
> >> +                       val = prop->value;
> >> +                       safe_frequency = be32_to_cpup(val++);
> >> +                       safe_voltage = be32_to_cpup(val);
> >> +               } else {
> >> +                       pr_err("invalid safe-opp level
> >> specified\n");
> >> +               }
> >> +       }
> >> +
> >>         of_property_read_u32(np, "voltage-tolerance",
> >> &voltage_tolerance);
> >>
> >>         if (of_property_read_u32(np, "clock-latency",
> >> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
> >>
> >>         if (!IS_ERR(cpu_reg)) {
> >> -               struct dev_pm_opp *opp;
> >>                 unsigned long min_uV, max_uV;
> >>                 int i;
> >>
> >> --
> >> 1.6.6.rc2
> >>



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28  8:17       ` Lukasz Majewski
@ 2014-01-28 11:36         ` Thomas Abraham
  2014-01-28 15:06           ` Lukasz Majewski
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-28 11:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Tue, Jan 28, 2014 at 1:47 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas, Mike
>
>> Hi Mike,
>>
>> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
>> <mturquette@linaro.org> wrote:
>> > Quoting Thomas Abraham (2014-01-18 04:10:51)
>> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >>
>> >> On some platforms such as the Samsung Exynos, changing the
>> >> frequency of the CPU clock requires changing the frequency of the
>> >> PLL that is supplying the CPU clock. To change the frequency of
>> >> the PLL, the CPU clock is temporarily reparented to another parent
>> >> clock.
>> >>
>> >> The clock frequency of this temporary parent clock could be much
>> >> higher than the clock frequency of the PLL at the time of
>> >> reparenting. Due to the temporary increase in the CPU clock speed,
>> >> the CPU (and any other components in the CPU clock domain such as
>> >> dividers, mux, etc.) have to to be operated at a higher voltage
>> >> level, called the safe voltage level. This patch adds optional
>> >> support to temporarily switch to a safe voltage level during CPU
>> >> frequency transitions.
>> >>
>> >> Cc: Shawn Guo <shawn.guo@linaro.org>
>> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >
>> > I'm not a fan of this change. This corner case should be abstracted
>> > away somehow. I had talked to Chander Kayshap previously about
>> > handling voltage changes in clock notifier callbacks, which then
>> > renders any voltage change as a trivial part of the clock rate
>> > transition. That means that this "safe voltage" thing could be
>> > handled automagically without any additional code in the CPUfreq
>> > driver.
>> >
>> > There are two nice ways to do this with the clock framework. First
>> > is explicit re-parenting with voltage scaling done in the clock
>> > rate-change notifiers:
>> >
>> > clk_set_parent(cpu_clk, temp_parent);
>> > /* implicit voltage scaling to "safe voltage" happens above */
>> > clk_set_rate(pll, some_rate);
>> > clk_set_parent(cpu_clk, pll);
>> > /* implicit voltage scaling to nominal OPP voltage happens above */
>> >
>
> I must agree with Mike here. In my opinion the above approach is more
> compliant with CCF (as I've pointed it out in my other comment - the
> cpu_clk has more than one parent and we could switch between them when
> needed).

The mux which is used to re-parent is part of the larger opaque cpu
clock type (more like the composite clock). So I am not sure how this
isn't compliant with ccf.

>
>> > The above sequence would require a separate exnyos CPUfreq driver,
>> > due to the added clk_set_parent logic.
>> >
>> > The second way to do this is to abstract the clk re-muxing logic out
>> > into the clk driver, which would allow cpufreq-cpu0 to be used for
>> > the exynos chips.
>>
>> This is the approach this patch series takes (patch 2/7). The clock
>> re-muxing logic is handled by a clock driver code. The difference from
>> what you suggested is that the safe voltage (that may be optionally)
>> required before doing the re-muxing is handled here in cpufreq-cpu0
>> driver.
>>
>> The safe voltage setup can be done in the notifier as you suggested.
>
> If the clk_set_parent() approach is not suitable, then cannot we
> consider using the one from highbank-cpufreq.c?
>
> Here we have cpufreq-cpu0.c which sets voltage of the cpu_clk.
> In the highbank-cpufreq.c there are clock notifiers to change the
> voltage.
>
> Cannot Exynos reuse such approach? Why shall we pollute cpufreq-cpu0.c
> with another solution?

The highbank-cpufreq.c file was introduced because platforms using
this driver did not have the usual regulator to control the voltage.
The first commit of this driver explains this (copied below).

"Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel."

So those platforms had no choice but to use an alternative approach to
control the voltage (and reuse cpufreq-cpu0 as much as possible). The
case with exynos is a different one. cpufreq-cpu0 is fully re-usable
for exynos with the additional support for "safe voltage". If we agree
that there might be existing or future platforms with single
clock/voltage rail that require the "safe voltage" feature, then
adding "safe voltage" support in cpufreq-cpu0 driver seems to be the
right approach.

>
>> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
>> this feature if required. Also, if done here, the regulator handling
>> is localized in this driver which otherwise would need to be handled
>> in two places, cpufreq-cpu0 driver and the clock notifier.
>
> I think that there is a logical distinction between setting voltage for
> cpufreq-cpu0 related clock and increasing voltage of reparented clock.
>
> The former fits naturally to cpufreq-cpu0, when the latter seems like
> some corner case (as Mike pointed out) for Exynos.

Agreed, it is a corner case. But for this corner case, we are
performing some additional actions on the same regulator which is used
in the normal functioning of the driver.

>
>>
>> So I tend to prefer the approach in this patch but I am willing to
>> consider any suggestions.
>
> Thomas, what do you think about highbank-cpufreq.c approach (with
> using clock notifiers)?

I have made a related comment on this above.

>
> Do you think, that it is feasible to reuse it with Exynos?

highbank cpufreq driver is intended for a different purpose so I don't
think it can be reused for exynos. Yes, we can make exynos specific
hacks into highbank driver but how would that be better over the
approach in this patch?

>
>> Shawn, it would be helpful if you could let
>> us know your thoughts on this. I am almost done with testing the v3 of
>> this series and want to post it so if there are any objections to the
>> changes in this patch, please let me know.
>>
>> Thanks,
>> Thomas.
>>
>> >
>> > I'm more a fan of explicitly listing the Exact Steps for the cpu opp
>> > transition in a separate exynos-specific CPUfreq driver, but that's
>> > probably an unpopular view.
>> >
>> > Regards,
>> > Mike
>> >
>> >> ---
>> >>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>> >>  drivers/cpufreq/cpufreq-cpu0.c                     |   37
>> >> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4
>> >> deletions(-)
>> >>
>> >> diff --git
>> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
>> >> f055515..37453ab 100644 ---
>> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
>> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@
>> >> -19,6 +19,12 @@ Optional properties:
>> >>  - cooling-min-level:
>> >>  - cooling-max-level:
>> >>       Please refer to
>> >> Documentation/devicetree/bindings/thermal/thermal.txt. +-
>> >> safe-opp: Certain platforms require that during a opp transition,
>> >> +  a system should not go below a particular opp level. For such
>> >> systems,
>> >> +  this property specifies the minimum opp to be maintained during
>> >> the
>> >> +  opp transitions. The safe-opp value is a tuple with first
>> >> element
>> >> +  representing the safe frequency and the second element
>> >> representing the
>> >> +  safe voltage.
>> >>
>> >>  Examples:
>> >>
>> >> @@ -36,6 +42,7 @@ cpus {
>> >>                         396000  950000
>> >>                         198000  850000
>> >>                 >;
>> >> +               safe-opp = <396000 950000>
>> >>                 clock-latency = <61036>; /* two CLK32 periods */
>> >>                 #cooling-cells = <2>;
>> >>                 cooling-min-level = <0>;
>> >> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
>> >> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
>> >> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> >> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> >> @@ -27,6 +27,8 @@
>> >>
>> >>  static unsigned int transition_latency;
>> >>  static unsigned int voltage_tolerance; /* in percentage */
>> >> +static unsigned long safe_frequency;
>> >> +static unsigned long safe_voltage;
>> >>
>> >>  static struct device *cpu_dev;
>> >>  static struct clk *cpu_clk;
>> >> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct
>> >> cpufreq_policy *policy, unsigned int index) volt_old =
>> >> regulator_get_voltage(cpu_reg); }
>> >>
>> >> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> >> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> >>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>> >>                  new_freq / 1000, volt ? volt / 1000 : -1);
>> >>
>> >>         /* scaling up?  scale voltage before frequency */
>> >> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>> >> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>> >> +                               new_freq >= safe_frequency) {
>> >>                 ret = regulator_set_voltage_tol(cpu_reg, volt,
>> >> tol); if (ret) {
>> >>                         pr_err("failed to scale voltage up: %d\n",
>> >> ret); return ret;
>> >>                 }
>> >> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>> >> +               /*
>> >> +                * the scaled up voltage level for the new_freq is
>> >> lower
>> >> +                * than the safe voltage level. so set safe_voltage
>> >> +                * as the intermediate voltage level and revert it
>> >> +                * back after the frequency has been changed.
>> >> +                */
>> >> +               ret = regulator_set_voltage_tol(cpu_reg,
>> >> safe_voltage, tol);
>> >> +               if (ret) {
>> >> +                       pr_err("failed to set safe voltage: %d\n",
>> >> ret);
>> >> +                       return ret;
>> >> +               }
>> >>         }
>> >>
>> >>         ret = clk_set_rate(cpu_clk, freq_exact);
>> >> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct
>> >> cpufreq_policy *policy, unsigned int index) }
>> >>
>> >>         /* scaling down?  scale voltage after frequency */
>> >> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>> >> +       if (!IS_ERR(cpu_reg) &&
>> >> +                       (new_freq < old_freq || new_freq <
>> >> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg, volt,
>> >> tol); if (ret) {
>> >>                         pr_err("failed to scale voltage down:
>> >> %d\n", ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
>> >> cpu0_cpufreq_driver = {
>> >>
>> >>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>> >>  {
>> >> +       const struct property *prop;
>> >> +       struct dev_pm_opp *opp;
>> >>         struct device_node *np;
>> >>         int ret;
>> >>
>> >> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
>> >> platform_device *pdev) goto out_put_node;
>> >>         }
>> >>
>> >> +       prop = of_find_property(np, "safe-opp", NULL);
>> >> +       if (prop) {
>> >> +               if (prop->value && (prop->length / sizeof(u32)) ==
>> >> 2) {
>> >> +                       const __be32 *val;
>> >> +                       val = prop->value;
>> >> +                       safe_frequency = be32_to_cpup(val++);
>> >> +                       safe_voltage = be32_to_cpup(val);
>> >> +               } else {
>> >> +                       pr_err("invalid safe-opp level
>> >> specified\n");
>> >> +               }
>> >> +       }
>> >> +
>> >>         of_property_read_u32(np, "voltage-tolerance",
>> >> &voltage_tolerance);
>> >>
>> >>         if (of_property_read_u32(np, "clock-latency",
>> >> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
>> >>
>> >>         if (!IS_ERR(cpu_reg)) {
>> >> -               struct dev_pm_opp *opp;
>> >>                 unsigned long min_uV, max_uV;
>> >>                 int i;
>> >>
>> >> --
>> >> 1.6.6.rc2
>> >>
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

Thanks for your comments Lukasz.

Regards,
Thomas.

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28  5:30     ` Thomas Abraham
  2014-01-28  8:17       ` Lukasz Majewski
@ 2014-01-28 11:49       ` Shawn Guo
  2014-01-28 12:47         ` Thomas Abraham
  2014-01-28 18:47       ` Mike Turquette
  2 siblings, 1 reply; 51+ messages in thread
From: Shawn Guo @ 2014-01-28 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 28, 2014 at 11:00:29AM +0530, Thomas Abraham wrote:
> Hi Mike,
> 
> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
> > Quoting Thomas Abraham (2014-01-18 04:10:51)
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> On some platforms such as the Samsung Exynos, changing the frequency
> >> of the CPU clock requires changing the frequency of the PLL that is
> >> supplying the CPU clock. To change the frequency of the PLL, the CPU
> >> clock is temporarily reparented to another parent clock.
> >>
> >> The clock frequency of this temporary parent clock could be much higher
> >> than the clock frequency of the PLL at the time of reparenting. Due
> >> to the temporary increase in the CPU clock speed, the CPU (and any other
> >> components in the CPU clock domain such as dividers, mux, etc.) have to
> >> to be operated at a higher voltage level, called the safe voltage level.
> >> This patch adds optional support to temporarily switch to a safe voltage
> >> level during CPU frequency transitions.
> >>
> >> Cc: Shawn Guo <shawn.guo@linaro.org>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >
> > I'm not a fan of this change. This corner case should be abstracted away
> > somehow. I had talked to Chander Kayshap previously about handling
> > voltage changes in clock notifier callbacks, which then renders any
> > voltage change as a trivial part of the clock rate transition. That
> > means that this "safe voltage" thing could be handled automagically
> > without any additional code in the CPUfreq driver.
> >
> > There are two nice ways to do this with the clock framework. First is
> > explicit re-parenting with voltage scaling done in the clock rate-change
> > notifiers:
> >
> > clk_set_parent(cpu_clk, temp_parent);
> > /* implicit voltage scaling to "safe voltage" happens above */
> > clk_set_rate(pll, some_rate);
> > clk_set_parent(cpu_clk, pll);
> > /* implicit voltage scaling to nominal OPP voltage happens above */
> >
> > The above sequence would require a separate exnyos CPUfreq driver, due
> > to the added clk_set_parent logic.
> >
> > The second way to do this is to abstract the clk re-muxing logic out
> > into the clk driver, which would allow cpufreq-cpu0 to be used for the
> > exynos chips.
> 
> This is the approach this patch series takes (patch 2/7). The clock
> re-muxing logic is handled by a clock driver code. The difference from
> what you suggested is that the safe voltage (that may be optionally)
> required before doing the re-muxing is handled here in cpufreq-cpu0
> driver.
> 
> The safe voltage setup can be done in the notifier as you suggested.
> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
> this feature if required. Also, if done here, the regulator handling
> is localized in this driver which otherwise would need to be handled
> in two places, cpufreq-cpu0 driver and the clock notifier.
> 
> So I tend to prefer the approach in this patch but I am willing to
> consider any suggestions. Shawn, it would be helpful if you could let
> us know your thoughts on this. I am almost done with testing the v3 of
> this series and want to post it so if there are any objections to the
> changes in this patch, please let me know.

To me, it's the best that we reuse cpufreq-cpu0 for exynos without any
changes on cpufreq-cpu0 driver ;)

Shawn

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28 11:49       ` Shawn Guo
@ 2014-01-28 12:47         ` Thomas Abraham
  0 siblings, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-28 12:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 28, 2014 at 5:19 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Tue, Jan 28, 2014 at 11:00:29AM +0530, Thomas Abraham wrote:
>> Hi Mike,
>>
>> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
>> > Quoting Thomas Abraham (2014-01-18 04:10:51)
>> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >>
>> >> On some platforms such as the Samsung Exynos, changing the frequency
>> >> of the CPU clock requires changing the frequency of the PLL that is
>> >> supplying the CPU clock. To change the frequency of the PLL, the CPU
>> >> clock is temporarily reparented to another parent clock.
>> >>
>> >> The clock frequency of this temporary parent clock could be much higher
>> >> than the clock frequency of the PLL at the time of reparenting. Due
>> >> to the temporary increase in the CPU clock speed, the CPU (and any other
>> >> components in the CPU clock domain such as dividers, mux, etc.) have to
>> >> to be operated at a higher voltage level, called the safe voltage level.
>> >> This patch adds optional support to temporarily switch to a safe voltage
>> >> level during CPU frequency transitions.
>> >>
>> >> Cc: Shawn Guo <shawn.guo@linaro.org>
>> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >
>> > I'm not a fan of this change. This corner case should be abstracted away
>> > somehow. I had talked to Chander Kayshap previously about handling
>> > voltage changes in clock notifier callbacks, which then renders any
>> > voltage change as a trivial part of the clock rate transition. That
>> > means that this "safe voltage" thing could be handled automagically
>> > without any additional code in the CPUfreq driver.
>> >
>> > There are two nice ways to do this with the clock framework. First is
>> > explicit re-parenting with voltage scaling done in the clock rate-change
>> > notifiers:
>> >
>> > clk_set_parent(cpu_clk, temp_parent);
>> > /* implicit voltage scaling to "safe voltage" happens above */
>> > clk_set_rate(pll, some_rate);
>> > clk_set_parent(cpu_clk, pll);
>> > /* implicit voltage scaling to nominal OPP voltage happens above */
>> >
>> > The above sequence would require a separate exnyos CPUfreq driver, due
>> > to the added clk_set_parent logic.
>> >
>> > The second way to do this is to abstract the clk re-muxing logic out
>> > into the clk driver, which would allow cpufreq-cpu0 to be used for the
>> > exynos chips.
>>
>> This is the approach this patch series takes (patch 2/7). The clock
>> re-muxing logic is handled by a clock driver code. The difference from
>> what you suggested is that the safe voltage (that may be optionally)
>> required before doing the re-muxing is handled here in cpufreq-cpu0
>> driver.
>>
>> The safe voltage setup can be done in the notifier as you suggested.
>> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
>> this feature if required. Also, if done here, the regulator handling
>> is localized in this driver which otherwise would need to be handled
>> in two places, cpufreq-cpu0 driver and the clock notifier.
>>
>> So I tend to prefer the approach in this patch but I am willing to
>> consider any suggestions. Shawn, it would be helpful if you could let
>> us know your thoughts on this. I am almost done with testing the v3 of
>> this series and want to post it so if there are any objections to the
>> changes in this patch, please let me know.
>
> To me, it's the best that we reuse cpufreq-cpu0 for exynos without any
> changes on cpufreq-cpu0 driver ;)

Okay, so that leaves us with the only option of handling "safe
voltage" using clock notifier callbacks as suggested by Mike. So there
are two options - a samsung specific cpufreq driver handling the clock
notifiers (and reusing cpufreq-cpu0 driver) or the samsung clock
driver handles the clock notifiers (and reusing cpufreq-cpu0 driver).

With the second option, the clock driver will have to handle the
regulator lookup from the cpu node, deferring regulator lookup until
the cpu and regulator devices are registered and using regulator api
inside clock driver. This seems like too much code to just manage the
"safe voltage".

So how about the first option of samsung specific cpufreq driver. If
there are any other alternatives, please let me know.

Thanks,
Thomas.

>
> Shawn
>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28 11:36         ` Thomas Abraham
@ 2014-01-28 15:06           ` Lukasz Majewski
  2014-01-28 15:15             ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-01-28 15:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> Hi Lukasz,
> 
> On Tue, Jan 28, 2014 at 1:47 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas, Mike
> >
> >> Hi Mike,
> >>
> >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
> >> <mturquette@linaro.org> wrote:
> >> > Quoting Thomas Abraham (2014-01-18 04:10:51)
> >> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >> >>
> >> >> On some platforms such as the Samsung Exynos, changing the
> >> >> frequency of the CPU clock requires changing the frequency of
> >> >> the PLL that is supplying the CPU clock. To change the
> >> >> frequency of the PLL, the CPU clock is temporarily reparented
> >> >> to another parent clock.
> >> >>
> >> >> The clock frequency of this temporary parent clock could be much
> >> >> higher than the clock frequency of the PLL at the time of
> >> >> reparenting. Due to the temporary increase in the CPU clock
> >> >> speed, the CPU (and any other components in the CPU clock
> >> >> domain such as dividers, mux, etc.) have to to be operated at a
> >> >> higher voltage level, called the safe voltage level. This patch
> >> >> adds optional support to temporarily switch to a safe voltage
> >> >> level during CPU frequency transitions.
> >> >>
> >> >> Cc: Shawn Guo <shawn.guo@linaro.org>
> >> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> >
> >> > I'm not a fan of this change. This corner case should be
> >> > abstracted away somehow. I had talked to Chander Kayshap
> >> > previously about handling voltage changes in clock notifier
> >> > callbacks, which then renders any voltage change as a trivial
> >> > part of the clock rate transition. That means that this "safe
> >> > voltage" thing could be handled automagically without any
> >> > additional code in the CPUfreq driver.
> >> >
> >> > There are two nice ways to do this with the clock framework.
> >> > First is explicit re-parenting with voltage scaling done in the
> >> > clock rate-change notifiers:
> >> >
> >> > clk_set_parent(cpu_clk, temp_parent);
> >> > /* implicit voltage scaling to "safe voltage" happens above */
> >> > clk_set_rate(pll, some_rate);
> >> > clk_set_parent(cpu_clk, pll);
> >> > /* implicit voltage scaling to nominal OPP voltage happens above
> >> > */
> >> >
> >
> > I must agree with Mike here. In my opinion the above approach is
> > more compliant with CCF (as I've pointed it out in my other comment
> > - the cpu_clk has more than one parent and we could switch between
> > them when needed).
> 
> The mux which is used to re-parent is part of the larger opaque cpu
> clock type (more like the composite clock). So I am not sure how this
> isn't compliant with ccf.

My point here is to use the clk_set_parent() explicitly instead of
changing the mux with writing values directly to registers.

However, I'm also aware, that we must reparent quickly. so I'm OK
with your approach.

> 
> >
> >> > The above sequence would require a separate exnyos CPUfreq
> >> > driver, due to the added clk_set_parent logic.
> >> >
> >> > The second way to do this is to abstract the clk re-muxing logic
> >> > out into the clk driver, which would allow cpufreq-cpu0 to be
> >> > used for the exynos chips.
> >>
> >> This is the approach this patch series takes (patch 2/7). The clock
> >> re-muxing logic is handled by a clock driver code. The difference
> >> from what you suggested is that the safe voltage (that may be
> >> optionally) required before doing the re-muxing is handled here in
> >> cpufreq-cpu0 driver.
> >>
> >> The safe voltage setup can be done in the notifier as you
> >> suggested.
> >
> > If the clk_set_parent() approach is not suitable, then cannot we
> > consider using the one from highbank-cpufreq.c?
> >
> > Here we have cpufreq-cpu0.c which sets voltage of the cpu_clk.
> > In the highbank-cpufreq.c there are clock notifiers to change the
> > voltage.
> >
> > Cannot Exynos reuse such approach? Why shall we pollute
> > cpufreq-cpu0.c with another solution?
> 
> The highbank-cpufreq.c file was introduced because platforms using
> this driver did not have the usual regulator to control the voltage.
> The first commit of this driver explains this (copied below).
> 
> "Highbank processors depend on the external ECME to perform voltage
> management based on a requested frequency. Communication between the
> A9 cores and the ECME happens over the pl320 IPC channel."
> 
> So those platforms had no choice but to use an alternative approach to
> control the voltage (and reuse cpufreq-cpu0 as much as possible). 
> The
> case with exynos is a different one.

Highbank needs to set voltage via IPC, Exynos needs to adjust voltage
when reparenting.

Both can be recognized as unusual cases. That is why I asked if we
could reuse the same approach for Exynos.

> cpufreq-cpu0 is fully re-usable
> for exynos with the additional support for "safe voltage". If we agree
> that there might be existing or future platforms with single
> clock/voltage rail that require the "safe voltage" feature, then
> adding "safe voltage" support in cpufreq-cpu0 driver seems to be the
> right approach.

I think that Shawn's opinion will be final here.

> 
> >
> >> But, doing that in cpufreq-cpu0 driver will help other platforms
> >> reuse this feature if required. Also, if done here, the regulator
> >> handling is localized in this driver which otherwise would need to
> >> be handled in two places, cpufreq-cpu0 driver and the clock
> >> notifier.
> >
> > I think that there is a logical distinction between setting voltage
> > for cpufreq-cpu0 related clock and increasing voltage of reparented
> > clock.
> >
> > The former fits naturally to cpufreq-cpu0, when the latter seems
> > like some corner case (as Mike pointed out) for Exynos.
> 
> Agreed, it is a corner case. But for this corner case, we are
> performing some additional actions on the same regulator which is used
> in the normal functioning of the driver.
> 
> >
> >>
> >> So I tend to prefer the approach in this patch but I am willing to
> >> consider any suggestions.
> >
> > Thomas, what do you think about highbank-cpufreq.c approach (with
> > using clock notifiers)?
> 
> I have made a related comment on this above.
> 
> >
> > Do you think, that it is feasible to reuse it with Exynos?
> 
> highbank cpufreq driver is intended for a different purpose so I don't
> think it can be reused for exynos. Yes, we can make exynos specific
> hacks into highbank driver but how would that be better over the
> approach in this patch?

I think, that I was misunderstood here. I wanted to ask if we could
reuse the clk notifier approach.

> 
> >
> >> Shawn, it would be helpful if you could let
> >> us know your thoughts on this. I am almost done with testing the
> >> v3 of this series and want to post it so if there are any
> >> objections to the changes in this patch, please let me know.
> >>
> >> Thanks,
> >> Thomas.
> >>
> >> >
> >> > I'm more a fan of explicitly listing the Exact Steps for the cpu
> >> > opp transition in a separate exynos-specific CPUfreq driver, but
> >> > that's probably an unpopular view.
> >> >
> >> > Regards,
> >> > Mike
> >> >
> >> >> ---
> >> >>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
> >> >>  drivers/cpufreq/cpufreq-cpu0.c                     |   37
> >> >> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4
> >> >> deletions(-)
> >> >>
> >> >> diff --git
> >> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> >> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> >> >> index f055515..37453ab 100644 ---
> >> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> >> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@
> >> >> -19,6 +19,12 @@ Optional properties:
> >> >>  - cooling-min-level:
> >> >>  - cooling-max-level:
> >> >>       Please refer to
> >> >> Documentation/devicetree/bindings/thermal/thermal.txt. +-
> >> >> safe-opp: Certain platforms require that during a opp
> >> >> transition,
> >> >> +  a system should not go below a particular opp level. For such
> >> >> systems,
> >> >> +  this property specifies the minimum opp to be maintained
> >> >> during the
> >> >> +  opp transitions. The safe-opp value is a tuple with first
> >> >> element
> >> >> +  representing the safe frequency and the second element
> >> >> representing the
> >> >> +  safe voltage.
> >> >>
> >> >>  Examples:
> >> >>
> >> >> @@ -36,6 +42,7 @@ cpus {
> >> >>                         396000  950000
> >> >>                         198000  850000
> >> >>                 >;
> >> >> +               safe-opp = <396000 950000>
> >> >>                 clock-latency = <61036>; /* two CLK32 periods */
> >> >>                 #cooling-cells = <2>;
> >> >>                 cooling-min-level = <0>;
> >> >> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> >> >> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
> >> >> --- a/drivers/cpufreq/cpufreq-cpu0.c
> >> >> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> >> >> @@ -27,6 +27,8 @@
> >> >>
> >> >>  static unsigned int transition_latency;
> >> >>  static unsigned int voltage_tolerance; /* in percentage */
> >> >> +static unsigned long safe_frequency;
> >> >> +static unsigned long safe_voltage;
> >> >>
> >> >>  static struct device *cpu_dev;
> >> >>  static struct clk *cpu_clk;
> >> >> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct
> >> >> cpufreq_policy *policy, unsigned int index) volt_old =
> >> >> regulator_get_voltage(cpu_reg); }
> >> >>
> >> >> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >> >> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >> >>                  old_freq / 1000, volt_old ? volt_old / 1000 :
> >> >> -1, new_freq / 1000, volt ? volt / 1000 : -1);
> >> >>
> >> >>         /* scaling up?  scale voltage before frequency */
> >> >> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> >> >> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> >> >> +                               new_freq >= safe_frequency) {
> >> >>                 ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> >> tol); if (ret) {
> >> >>                         pr_err("failed to scale voltage up:
> >> >> %d\n", ret); return ret;
> >> >>                 }
> >> >> +       } else if (!IS_ERR(cpu_reg) && old_freq <
> >> >> safe_frequency) {
> >> >> +               /*
> >> >> +                * the scaled up voltage level for the new_freq
> >> >> is lower
> >> >> +                * than the safe voltage level. so set
> >> >> safe_voltage
> >> >> +                * as the intermediate voltage level and revert
> >> >> it
> >> >> +                * back after the frequency has been changed.
> >> >> +                */
> >> >> +               ret = regulator_set_voltage_tol(cpu_reg,
> >> >> safe_voltage, tol);
> >> >> +               if (ret) {
> >> >> +                       pr_err("failed to set safe voltage:
> >> >> %d\n", ret);
> >> >> +                       return ret;
> >> >> +               }
> >> >>         }
> >> >>
> >> >>         ret = clk_set_rate(cpu_clk, freq_exact);
> >> >> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct
> >> >> cpufreq_policy *policy, unsigned int index) }
> >> >>
> >> >>         /* scaling down?  scale voltage after frequency */
> >> >> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> >> >> +       if (!IS_ERR(cpu_reg) &&
> >> >> +                       (new_freq < old_freq || new_freq <
> >> >> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg,
> >> >> volt, tol); if (ret) {
> >> >>                         pr_err("failed to scale voltage down:
> >> >> %d\n", ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
> >> >> cpu0_cpufreq_driver = {
> >> >>
> >> >>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
> >> >>  {
> >> >> +       const struct property *prop;
> >> >> +       struct dev_pm_opp *opp;
> >> >>         struct device_node *np;
> >> >>         int ret;
> >> >>
> >> >> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
> >> >> platform_device *pdev) goto out_put_node;
> >> >>         }
> >> >>
> >> >> +       prop = of_find_property(np, "safe-opp", NULL);
> >> >> +       if (prop) {
> >> >> +               if (prop->value && (prop->length / sizeof(u32))
> >> >> == 2) {
> >> >> +                       const __be32 *val;
> >> >> +                       val = prop->value;
> >> >> +                       safe_frequency = be32_to_cpup(val++);
> >> >> +                       safe_voltage = be32_to_cpup(val);
> >> >> +               } else {
> >> >> +                       pr_err("invalid safe-opp level
> >> >> specified\n");
> >> >> +               }
> >> >> +       }
> >> >> +
> >> >>         of_property_read_u32(np, "voltage-tolerance",
> >> >> &voltage_tolerance);
> >> >>
> >> >>         if (of_property_read_u32(np, "clock-latency",
> >> >> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
> >> >>
> >> >>         if (!IS_ERR(cpu_reg)) {
> >> >> -               struct dev_pm_opp *opp;
> >> >>                 unsigned long min_uV, max_uV;
> >> >>                 int i;
> >> >>
> >> >> --
> >> >> 1.6.6.rc2
> >> >>
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> 
> Thanks for your comments Lukasz.
> 
> Regards,
> Thomas.
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28 15:06           ` Lukasz Majewski
@ 2014-01-28 15:15             ` Thomas Abraham
  0 siblings, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-01-28 15:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Tue, Jan 28, 2014 at 8:36 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> Hi Lukasz,
>>
>> On Tue, Jan 28, 2014 at 1:47 PM, Lukasz Majewski
>> <l.majewski@samsung.com> wrote:
>> > Hi Thomas, Mike
>> >
>> >> Hi Mike,
>> >>
>> >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
>> >> <mturquette@linaro.org> wrote:
>> >> > Quoting Thomas Abraham (2014-01-18 04:10:51)
>> >> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >> >>
>> >> >> On some platforms such as the Samsung Exynos, changing the
>> >> >> frequency of the CPU clock requires changing the frequency of
>> >> >> the PLL that is supplying the CPU clock. To change the
>> >> >> frequency of the PLL, the CPU clock is temporarily reparented
>> >> >> to another parent clock.
>> >> >>
>> >> >> The clock frequency of this temporary parent clock could be much
>> >> >> higher than the clock frequency of the PLL at the time of
>> >> >> reparenting. Due to the temporary increase in the CPU clock
>> >> >> speed, the CPU (and any other components in the CPU clock
>> >> >> domain such as dividers, mux, etc.) have to to be operated at a
>> >> >> higher voltage level, called the safe voltage level. This patch
>> >> >> adds optional support to temporarily switch to a safe voltage
>> >> >> level during CPU frequency transitions.
>> >> >>
>> >> >> Cc: Shawn Guo <shawn.guo@linaro.org>
>> >> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >> >
>> >> > I'm not a fan of this change. This corner case should be
>> >> > abstracted away somehow. I had talked to Chander Kayshap
>> >> > previously about handling voltage changes in clock notifier
>> >> > callbacks, which then renders any voltage change as a trivial
>> >> > part of the clock rate transition. That means that this "safe
>> >> > voltage" thing could be handled automagically without any
>> >> > additional code in the CPUfreq driver.
>> >> >
>> >> > There are two nice ways to do this with the clock framework.
>> >> > First is explicit re-parenting with voltage scaling done in the
>> >> > clock rate-change notifiers:
>> >> >
>> >> > clk_set_parent(cpu_clk, temp_parent);
>> >> > /* implicit voltage scaling to "safe voltage" happens above */
>> >> > clk_set_rate(pll, some_rate);
>> >> > clk_set_parent(cpu_clk, pll);
>> >> > /* implicit voltage scaling to nominal OPP voltage happens above
>> >> > */
>> >> >
>> >
>> > I must agree with Mike here. In my opinion the above approach is
>> > more compliant with CCF (as I've pointed it out in my other comment
>> > - the cpu_clk has more than one parent and we could switch between
>> > them when needed).
>>
>> The mux which is used to re-parent is part of the larger opaque cpu
>> clock type (more like the composite clock). So I am not sure how this
>> isn't compliant with ccf.
>
> My point here is to use the clk_set_parent() explicitly instead of
> changing the mux with writing values directly to registers.
>
> However, I'm also aware, that we must reparent quickly. so I'm OK
> with your approach.

Okay.

>
>>
>> >
>> >> > The above sequence would require a separate exnyos CPUfreq
>> >> > driver, due to the added clk_set_parent logic.
>> >> >
>> >> > The second way to do this is to abstract the clk re-muxing logic
>> >> > out into the clk driver, which would allow cpufreq-cpu0 to be
>> >> > used for the exynos chips.
>> >>
>> >> This is the approach this patch series takes (patch 2/7). The clock
>> >> re-muxing logic is handled by a clock driver code. The difference
>> >> from what you suggested is that the safe voltage (that may be
>> >> optionally) required before doing the re-muxing is handled here in
>> >> cpufreq-cpu0 driver.
>> >>
>> >> The safe voltage setup can be done in the notifier as you
>> >> suggested.
>> >
>> > If the clk_set_parent() approach is not suitable, then cannot we
>> > consider using the one from highbank-cpufreq.c?
>> >
>> > Here we have cpufreq-cpu0.c which sets voltage of the cpu_clk.
>> > In the highbank-cpufreq.c there are clock notifiers to change the
>> > voltage.
>> >
>> > Cannot Exynos reuse such approach? Why shall we pollute
>> > cpufreq-cpu0.c with another solution?
>>
>> The highbank-cpufreq.c file was introduced because platforms using
>> this driver did not have the usual regulator to control the voltage.
>> The first commit of this driver explains this (copied below).
>>
>> "Highbank processors depend on the external ECME to perform voltage
>> management based on a requested frequency. Communication between the
>> A9 cores and the ECME happens over the pl320 IPC channel."
>>
>> So those platforms had no choice but to use an alternative approach to
>> control the voltage (and reuse cpufreq-cpu0 as much as possible).
>> The
>> case with exynos is a different one.
>
> Highbank needs to set voltage via IPC, Exynos needs to adjust voltage
> when reparenting.
>
> Both can be recognized as unusual cases. That is why I asked if we
> could reuse the same approach for Exynos.

Okay.

>
>> cpufreq-cpu0 is fully re-usable
>> for exynos with the additional support for "safe voltage". If we agree
>> that there might be existing or future platforms with single
>> clock/voltage rail that require the "safe voltage" feature, then
>> adding "safe voltage" support in cpufreq-cpu0 driver seems to be the
>> right approach.
>
> I think that Shawn's opinion will be final here.
>
>>
>> >
>> >> But, doing that in cpufreq-cpu0 driver will help other platforms
>> >> reuse this feature if required. Also, if done here, the regulator
>> >> handling is localized in this driver which otherwise would need to
>> >> be handled in two places, cpufreq-cpu0 driver and the clock
>> >> notifier.
>> >
>> > I think that there is a logical distinction between setting voltage
>> > for cpufreq-cpu0 related clock and increasing voltage of reparented
>> > clock.
>> >
>> > The former fits naturally to cpufreq-cpu0, when the latter seems
>> > like some corner case (as Mike pointed out) for Exynos.
>>
>> Agreed, it is a corner case. But for this corner case, we are
>> performing some additional actions on the same regulator which is used
>> in the normal functioning of the driver.
>>
>> >
>> >>
>> >> So I tend to prefer the approach in this patch but I am willing to
>> >> consider any suggestions.
>> >
>> > Thomas, what do you think about highbank-cpufreq.c approach (with
>> > using clock notifiers)?
>>
>> I have made a related comment on this above.
>>
>> >
>> > Do you think, that it is feasible to reuse it with Exynos?
>>
>> highbank cpufreq driver is intended for a different purpose so I don't
>> think it can be reused for exynos. Yes, we can make exynos specific
>> hacks into highbank driver but how would that be better over the
>> approach in this patch?
>
> I think, that I was misunderstood here. I wanted to ask if we could
> reuse the clk notifier approach.

Okay, I misunderstood your comment. We could do something similar to
highbank cpufreq driver for exynos as well. Anyways, Shawn prefers not
to add "safe voltage" support into cpufreq-cpu0 driver. So we need to
look for other options.

Thanks,
Thomas.

>
>>
>> >
>> >> Shawn, it would be helpful if you could let
>> >> us know your thoughts on this. I am almost done with testing the
>> >> v3 of this series and want to post it so if there are any
>> >> objections to the changes in this patch, please let me know.
>> >>
>> >> Thanks,
>> >> Thomas.
>> >>
>> >> >
>> >> > I'm more a fan of explicitly listing the Exact Steps for the cpu
>> >> > opp transition in a separate exynos-specific CPUfreq driver, but
>> >> > that's probably an unpopular view.
>> >> >
>> >> > Regards,
>> >> > Mike
>> >> >
>> >> >> ---
>> >> >>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>> >> >>  drivers/cpufreq/cpufreq-cpu0.c                     |   37
>> >> >> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4
>> >> >> deletions(-)
>> >> >>
>> >> >> diff --git
>> >> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> >> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> >> >> index f055515..37453ab 100644 ---
>> >> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
>> >> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@
>> >> >> -19,6 +19,12 @@ Optional properties:
>> >> >>  - cooling-min-level:
>> >> >>  - cooling-max-level:
>> >> >>       Please refer to
>> >> >> Documentation/devicetree/bindings/thermal/thermal.txt. +-
>> >> >> safe-opp: Certain platforms require that during a opp
>> >> >> transition,
>> >> >> +  a system should not go below a particular opp level. For such
>> >> >> systems,
>> >> >> +  this property specifies the minimum opp to be maintained
>> >> >> during the
>> >> >> +  opp transitions. The safe-opp value is a tuple with first
>> >> >> element
>> >> >> +  representing the safe frequency and the second element
>> >> >> representing the
>> >> >> +  safe voltage.
>> >> >>
>> >> >>  Examples:
>> >> >>
>> >> >> @@ -36,6 +42,7 @@ cpus {
>> >> >>                         396000  950000
>> >> >>                         198000  850000
>> >> >>                 >;
>> >> >> +               safe-opp = <396000 950000>
>> >> >>                 clock-latency = <61036>; /* two CLK32 periods */
>> >> >>                 #cooling-cells = <2>;
>> >> >>                 cooling-min-level = <0>;
>> >> >> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
>> >> >> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
>> >> >> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> >> >> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> >> >> @@ -27,6 +27,8 @@
>> >> >>
>> >> >>  static unsigned int transition_latency;
>> >> >>  static unsigned int voltage_tolerance; /* in percentage */
>> >> >> +static unsigned long safe_frequency;
>> >> >> +static unsigned long safe_voltage;
>> >> >>
>> >> >>  static struct device *cpu_dev;
>> >> >>  static struct clk *cpu_clk;
>> >> >> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct
>> >> >> cpufreq_policy *policy, unsigned int index) volt_old =
>> >> >> regulator_get_voltage(cpu_reg); }
>> >> >>
>> >> >> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> >> >> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>> >> >>                  old_freq / 1000, volt_old ? volt_old / 1000 :
>> >> >> -1, new_freq / 1000, volt ? volt / 1000 : -1);
>> >> >>
>> >> >>         /* scaling up?  scale voltage before frequency */
>> >> >> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>> >> >> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>> >> >> +                               new_freq >= safe_frequency) {
>> >> >>                 ret = regulator_set_voltage_tol(cpu_reg, volt,
>> >> >> tol); if (ret) {
>> >> >>                         pr_err("failed to scale voltage up:
>> >> >> %d\n", ret); return ret;
>> >> >>                 }
>> >> >> +       } else if (!IS_ERR(cpu_reg) && old_freq <
>> >> >> safe_frequency) {
>> >> >> +               /*
>> >> >> +                * the scaled up voltage level for the new_freq
>> >> >> is lower
>> >> >> +                * than the safe voltage level. so set
>> >> >> safe_voltage
>> >> >> +                * as the intermediate voltage level and revert
>> >> >> it
>> >> >> +                * back after the frequency has been changed.
>> >> >> +                */
>> >> >> +               ret = regulator_set_voltage_tol(cpu_reg,
>> >> >> safe_voltage, tol);
>> >> >> +               if (ret) {
>> >> >> +                       pr_err("failed to set safe voltage:
>> >> >> %d\n", ret);
>> >> >> +                       return ret;
>> >> >> +               }
>> >> >>         }
>> >> >>
>> >> >>         ret = clk_set_rate(cpu_clk, freq_exact);
>> >> >> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct
>> >> >> cpufreq_policy *policy, unsigned int index) }
>> >> >>
>> >> >>         /* scaling down?  scale voltage after frequency */
>> >> >> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>> >> >> +       if (!IS_ERR(cpu_reg) &&
>> >> >> +                       (new_freq < old_freq || new_freq <
>> >> >> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg,
>> >> >> volt, tol); if (ret) {
>> >> >>                         pr_err("failed to scale voltage down:
>> >> >> %d\n", ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
>> >> >> cpu0_cpufreq_driver = {
>> >> >>
>> >> >>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>> >> >>  {
>> >> >> +       const struct property *prop;
>> >> >> +       struct dev_pm_opp *opp;
>> >> >>         struct device_node *np;
>> >> >>         int ret;
>> >> >>
>> >> >> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
>> >> >> platform_device *pdev) goto out_put_node;
>> >> >>         }
>> >> >>
>> >> >> +       prop = of_find_property(np, "safe-opp", NULL);
>> >> >> +       if (prop) {
>> >> >> +               if (prop->value && (prop->length / sizeof(u32))
>> >> >> == 2) {
>> >> >> +                       const __be32 *val;
>> >> >> +                       val = prop->value;
>> >> >> +                       safe_frequency = be32_to_cpup(val++);
>> >> >> +                       safe_voltage = be32_to_cpup(val);
>> >> >> +               } else {
>> >> >> +                       pr_err("invalid safe-opp level
>> >> >> specified\n");
>> >> >> +               }
>> >> >> +       }
>> >> >> +
>> >> >>         of_property_read_u32(np, "voltage-tolerance",
>> >> >> &voltage_tolerance);
>> >> >>
>> >> >>         if (of_property_read_u32(np, "clock-latency",
>> >> >> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
>> >> >>
>> >> >>         if (!IS_ERR(cpu_reg)) {
>> >> >> -               struct dev_pm_opp *opp;
>> >> >>                 unsigned long min_uV, max_uV;
>> >> >>                 int i;
>> >> >>
>> >> >> --
>> >> >> 1.6.6.rc2
>> >> >>
>> >
>> >
>> >
>> > --
>> > Best regards,
>> >
>> > Lukasz Majewski
>> >
>> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
>>
>> Thanks for your comments Lukasz.
>>
>> Regards,
>> Thomas.
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28  5:30     ` Thomas Abraham
  2014-01-28  8:17       ` Lukasz Majewski
  2014-01-28 11:49       ` Shawn Guo
@ 2014-01-28 18:47       ` Mike Turquette
  2014-01-30 12:53         ` Thomas Abraham
  2 siblings, 1 reply; 51+ messages in thread
From: Mike Turquette @ 2014-01-28 18:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com> wrote:
> Hi Mike,
>
> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
>> Quoting Thomas Abraham (2014-01-18 04:10:51)
>>> From: Thomas Abraham <thomas.ab@samsung.com>
>>>
>>> On some platforms such as the Samsung Exynos, changing the frequency
>>> of the CPU clock requires changing the frequency of the PLL that is
>>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>>> clock is temporarily reparented to another parent clock.
>>>
>>> The clock frequency of this temporary parent clock could be much higher
>>> than the clock frequency of the PLL at the time of reparenting. Due
>>> to the temporary increase in the CPU clock speed, the CPU (and any other
>>> components in the CPU clock domain such as dividers, mux, etc.) have to
>>> to be operated at a higher voltage level, called the safe voltage level.
>>> This patch adds optional support to temporarily switch to a safe voltage
>>> level during CPU frequency transitions.
>>>
>>> Cc: Shawn Guo <shawn.guo@linaro.org>
>>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>>
>> I'm not a fan of this change. This corner case should be abstracted away
>> somehow. I had talked to Chander Kayshap previously about handling
>> voltage changes in clock notifier callbacks, which then renders any
>> voltage change as a trivial part of the clock rate transition. That
>> means that this "safe voltage" thing could be handled automagically
>> without any additional code in the CPUfreq driver.
>>
>> There are two nice ways to do this with the clock framework. First is
>> explicit re-parenting with voltage scaling done in the clock rate-change
>> notifiers:
>>
>> clk_set_parent(cpu_clk, temp_parent);
>> /* implicit voltage scaling to "safe voltage" happens above */
>> clk_set_rate(pll, some_rate);
>> clk_set_parent(cpu_clk, pll);
>> /* implicit voltage scaling to nominal OPP voltage happens above */
>>
>> The above sequence would require a separate exnyos CPUfreq driver, due
>> to the added clk_set_parent logic.
>>
>> The second way to do this is to abstract the clk re-muxing logic out
>> into the clk driver, which would allow cpufreq-cpu0 to be used for the
>> exynos chips.
>
> This is the approach this patch series takes (patch 2/7). The clock
> re-muxing logic is handled by a clock driver code. The difference from
> what you suggested is that the safe voltage (that may be optionally)
> required before doing the re-muxing is handled here in cpufreq-cpu0
> driver.

Right, I understand the approach taken in this series and I'm not sure
it is the right one. Why does the clock driver handle the remuxing if
it is a functional dependency of the ARM core? As far as I can tell
the remux does not happen because it is necessary to generate the
required clock rate, but because we don't want to run the ARM core out
of spec for a short time while the PLL relocks. Assuming I have that
part of it right, I prefer for the parent mux operation to be a part
of the CPUfreq driver's .target callback instead of hidden away in the
clock driver.

A common pattern I'm seeing for the last 18 months is code
consolidation for the sake of code consolidation and it is not always
a good thing. Having hardware-specific machine drivers under
drivers/cpufreq/ is the right way to go, and we should only
consolidate a driver to cpufreq-cpu0 if it makes sense.

>
> The safe voltage setup can be done in the notifier as you suggested.
> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
> this feature if required. Also, if done here, the regulator handling
> is localized in this driver which otherwise would need to be handled
> in two places, cpufreq-cpu0 driver and the clock notifier.

The notifiers are reusable across other platforms. And the notifier
can be entirely set up within the cpufreq driver. Code location is not
a problem. See this RFC series:
https://lkml.org/lkml/2013/7/7/110

>
> So I tend to prefer the approach in this patch but I am willing to
> consider any suggestions. Shawn, it would be helpful if you could let
> us know your thoughts on this. I am almost done with testing the v3 of
> this series and want to post it so if there are any objections to the
> changes in this patch, please let me know.

Well I wonder if the whole approach could be more generalized. The DT
bindings for CPU frequencies could be used by any platform instead of
being Exynos-specific. We could construct a binding which captures an
arbitrary clock sub-tree snapshot. By that I mean a DT binding in
which any number of clocks and their parents and rates could be
specified in a table. Separately we could have a binding that links a
given clock at a given rate to some specified regulator and voltage.
So in this way the bindings are re-usable.

These DT ideas should be considered separately from the CPUfreq notes
outlined above, and I will respond to patch #3 in this series once I
have a chance.

Thanks,
Mike

>
> Thanks,
> Thomas.
>
>>
>> I'm more a fan of explicitly listing the Exact Steps for the cpu opp
>> transition in a separate exynos-specific CPUfreq driver, but that's
>> probably an unpopular view.
>>
>> Regards,
>> Mike
>>
>>> ---
>>>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>>>  drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
>>>  2 files changed, 40 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>> index f055515..37453ab 100644
>>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>> @@ -19,6 +19,12 @@ Optional properties:
>>>  - cooling-min-level:
>>>  - cooling-max-level:
>>>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>>> +- safe-opp: Certain platforms require that during a opp transition,
>>> +  a system should not go below a particular opp level. For such systems,
>>> +  this property specifies the minimum opp to be maintained during the
>>> +  opp transitions. The safe-opp value is a tuple with first element
>>> +  representing the safe frequency and the second element representing the
>>> +  safe voltage.
>>>
>>>  Examples:
>>>
>>> @@ -36,6 +42,7 @@ cpus {
>>>                         396000  950000
>>>                         198000  850000
>>>                 >;
>>> +               safe-opp = <396000 950000>
>>>                 clock-latency = <61036>; /* two CLK32 periods */
>>>                 #cooling-cells = <2>;
>>>                 cooling-min-level = <0>;
>>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>>> index 0c12ffc..075d3d1 100644
>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>> @@ -27,6 +27,8 @@
>>>
>>>  static unsigned int transition_latency;
>>>  static unsigned int voltage_tolerance; /* in percentage */
>>> +static unsigned long safe_frequency;
>>> +static unsigned long safe_voltage;
>>>
>>>  static struct device *cpu_dev;
>>>  static struct clk *cpu_clk;
>>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>>                 volt_old = regulator_get_voltage(cpu_reg);
>>>         }
>>>
>>> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>>>                  new_freq / 1000, volt ? volt / 1000 : -1);
>>>
>>>         /* scaling up?  scale voltage before frequency */
>>> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>>> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>>> +                               new_freq >= safe_frequency) {
>>>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>>                 if (ret) {
>>>                         pr_err("failed to scale voltage up: %d\n", ret);
>>>                         return ret;
>>>                 }
>>> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>>> +               /*
>>> +                * the scaled up voltage level for the new_freq is lower
>>> +                * than the safe voltage level. so set safe_voltage
>>> +                * as the intermediate voltage level and revert it
>>> +                * back after the frequency has been changed.
>>> +                */
>>> +               ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>>> +               if (ret) {
>>> +                       pr_err("failed to set safe voltage: %d\n", ret);
>>> +                       return ret;
>>> +               }
>>>         }
>>>
>>>         ret = clk_set_rate(cpu_clk, freq_exact);
>>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>>         }
>>>
>>>         /* scaling down?  scale voltage after frequency */
>>> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>>> +       if (!IS_ERR(cpu_reg) &&
>>> +                       (new_freq < old_freq || new_freq < safe_frequency)) {
>>>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>>                 if (ret) {
>>>                         pr_err("failed to scale voltage down: %d\n", ret);
>>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>>
>>>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>  {
>>> +       const struct property *prop;
>>> +       struct dev_pm_opp *opp;
>>>         struct device_node *np;
>>>         int ret;
>>>
>>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>                 goto out_put_node;
>>>         }
>>>
>>> +       prop = of_find_property(np, "safe-opp", NULL);
>>> +       if (prop) {
>>> +               if (prop->value && (prop->length / sizeof(u32)) == 2) {
>>> +                       const __be32 *val;
>>> +                       val = prop->value;
>>> +                       safe_frequency = be32_to_cpup(val++);
>>> +                       safe_voltage = be32_to_cpup(val);
>>> +               } else {
>>> +                       pr_err("invalid safe-opp level specified\n");
>>> +               }
>>> +       }
>>> +
>>>         of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>>
>>>         if (of_property_read_u32(np, "clock-latency", &transition_latency))
>>>                 transition_latency = CPUFREQ_ETERNAL;
>>>
>>>         if (!IS_ERR(cpu_reg)) {
>>> -               struct dev_pm_opp *opp;
>>>                 unsigned long min_uV, max_uV;
>>>                 int i;
>>>
>>> --
>>> 1.6.6.rc2
>>>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-28 18:47       ` Mike Turquette
@ 2014-01-30 12:53         ` Thomas Abraham
  2014-01-30 15:09           ` Heiko Stübner
  0 siblings, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-01-30 12:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mike,

On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org> wrote:
> On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com> wrote:
>> Hi Mike,
>>
>> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
>>> Quoting Thomas Abraham (2014-01-18 04:10:51)
>>>> From: Thomas Abraham <thomas.ab@samsung.com>
>>>>
>>>> On some platforms such as the Samsung Exynos, changing the frequency
>>>> of the CPU clock requires changing the frequency of the PLL that is
>>>> supplying the CPU clock. To change the frequency of the PLL, the CPU
>>>> clock is temporarily reparented to another parent clock.
>>>>
>>>> The clock frequency of this temporary parent clock could be much higher
>>>> than the clock frequency of the PLL at the time of reparenting. Due
>>>> to the temporary increase in the CPU clock speed, the CPU (and any other
>>>> components in the CPU clock domain such as dividers, mux, etc.) have to
>>>> to be operated at a higher voltage level, called the safe voltage level.
>>>> This patch adds optional support to temporarily switch to a safe voltage
>>>> level during CPU frequency transitions.
>>>>
>>>> Cc: Shawn Guo <shawn.guo@linaro.org>
>>>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>>>
>>> I'm not a fan of this change. This corner case should be abstracted away
>>> somehow. I had talked to Chander Kayshap previously about handling
>>> voltage changes in clock notifier callbacks, which then renders any
>>> voltage change as a trivial part of the clock rate transition. That
>>> means that this "safe voltage" thing could be handled automagically
>>> without any additional code in the CPUfreq driver.
>>>
>>> There are two nice ways to do this with the clock framework. First is
>>> explicit re-parenting with voltage scaling done in the clock rate-change
>>> notifiers:
>>>
>>> clk_set_parent(cpu_clk, temp_parent);
>>> /* implicit voltage scaling to "safe voltage" happens above */
>>> clk_set_rate(pll, some_rate);
>>> clk_set_parent(cpu_clk, pll);
>>> /* implicit voltage scaling to nominal OPP voltage happens above */
>>>
>>> The above sequence would require a separate exnyos CPUfreq driver, due
>>> to the added clk_set_parent logic.
>>>
>>> The second way to do this is to abstract the clk re-muxing logic out
>>> into the clk driver, which would allow cpufreq-cpu0 to be used for the
>>> exynos chips.
>>
>> This is the approach this patch series takes (patch 2/7). The clock
>> re-muxing logic is handled by a clock driver code. The difference from
>> what you suggested is that the safe voltage (that may be optionally)
>> required before doing the re-muxing is handled here in cpufreq-cpu0
>> driver.
>
> Right, I understand the approach taken in this series and I'm not sure
> it is the right one. Why does the clock driver handle the remuxing if
> it is a functional dependency of the ARM core?

The output of the PLL is the input to a tree of clock nodes. One of
the outputs from this tree is the clock to ARM. And the other outputs
do not serve as parents to any other clocks in the system but are used
internally in the bus interconnect. In addition to that, there are
clock speed restrictions for the clock outputs from this tree with
respect to speeds of other clocks in this clock tree.

Hence, this entire clock tree has been purged into a single composite
clock which includes mux and dividers. So the clock tree now looks
like PLL Output -> Custom Composite Clock -> ARM clock output.

But there is a problem when changing the ARM clock speed which in turn
causes change in PLL clock speed. When PLL clock speed has to be
changed, the PLL has to be first turned off. Which means the clock to
ARM core is cut-off. To avoid that, the Custom Composite Clock now has
to get its clock from another source until the PLL is ready to operate
again. So this composite clock does an automatic re-parenting (the mux
is within is composite clock) because it knows that it is its
responsibility to ensure clock ARM all the time.


> As far as I can tell
> the remux does not happen because it is necessary to generate the
> required clock rate, but because we don't want to run the ARM core out
> of spec for a short time while the PLL relocks. Assuming I have that
> part of it right, I prefer for the parent mux operation to be a part
> of the CPUfreq driver's .target callback instead of hidden away in the
> clock driver.

The re-parenting is mostly done to keep the ARM CPU clocked while the
PLL is stopped, reprogrammed and restarted. One of the side effects of
that is, the clock speed of the temporary parent could be higher then
what is allowed due to the ARM voltage at the time of re-parenting.
That is the reason to use the safe voltage.

>
> A common pattern I'm seeing for the last 18 months is code
> consolidation for the sake of code consolidation and it is not always
> a good thing. Having hardware-specific machine drivers under
> drivers/cpufreq/ is the right way to go, and we should only
> consolidate a driver to cpufreq-cpu0 if it makes sense.

Okay.I agree. And I did feel that adding the optional "safe voltage"
feature in cpufreq-cpu0 would help Exynos platforms reuse this driver.
And adding this feature in cpufreq-cpu did not feel like some
orthogonal approach but a logical extension.

>
>>
>> The safe voltage setup can be done in the notifier as you suggested.
>> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
>> this feature if required. Also, if done here, the regulator handling
>> is localized in this driver which otherwise would need to be handled
>> in two places, cpufreq-cpu0 driver and the clock notifier.
>
> The notifiers are reusable across other platforms. And the notifier
> can be entirely set up within the cpufreq driver. Code location is not
> a problem. See this RFC series:
> https://lkml.org/lkml/2013/7/7/110

Okay.

>
>>
>> So I tend to prefer the approach in this patch but I am willing to
>> consider any suggestions. Shawn, it would be helpful if you could let
>> us know your thoughts on this. I am almost done with testing the v3 of
>> this series and want to post it so if there are any objections to the
>> changes in this patch, please let me know.
>
> Well I wonder if the whole approach could be more generalized. The DT
> bindings for CPU frequencies could be used by any platform instead of
> being Exynos-specific. We could construct a binding which captures an
> arbitrary clock sub-tree snapshot. By that I mean a DT binding in
> which any number of clocks and their parents and rates could be
> specified in a table. Separately we could have a binding that links a
> given clock at a given rate to some specified regulator and voltage.
> So in this way the bindings are re-usable.
>
> These DT ideas should be considered separately from the CPUfreq notes
> outlined above, and I will respond to patch #3 in this series once I
> have a chance.

Okay. Thanks Mike for your comments. And sorry for the delay in my reply.

Regards,
Thomas.

>
> Thanks,
> Mike
>
>>
>> Thanks,
>> Thomas.
>>
>>>
>>> I'm more a fan of explicitly listing the Exact Steps for the cpu opp
>>> transition in a separate exynos-specific CPUfreq driver, but that's
>>> probably an unpopular view.
>>>
>>> Regards,
>>> Mike
>>>
>>>> ---
>>>>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
>>>>  drivers/cpufreq/cpufreq-cpu0.c                     |   37 +++++++++++++++++--
>>>>  2 files changed, 40 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>>> index f055515..37453ab 100644
>>>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>>>> @@ -19,6 +19,12 @@ Optional properties:
>>>>  - cooling-min-level:
>>>>  - cooling-max-level:
>>>>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>>>> +- safe-opp: Certain platforms require that during a opp transition,
>>>> +  a system should not go below a particular opp level. For such systems,
>>>> +  this property specifies the minimum opp to be maintained during the
>>>> +  opp transitions. The safe-opp value is a tuple with first element
>>>> +  representing the safe frequency and the second element representing the
>>>> +  safe voltage.
>>>>
>>>>  Examples:
>>>>
>>>> @@ -36,6 +42,7 @@ cpus {
>>>>                         396000  950000
>>>>                         198000  850000
>>>>                 >;
>>>> +               safe-opp = <396000 950000>
>>>>                 clock-latency = <61036>; /* two CLK32 periods */
>>>>                 #cooling-cells = <2>;
>>>>                 cooling-min-level = <0>;
>>>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>>>> index 0c12ffc..075d3d1 100644
>>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>>> @@ -27,6 +27,8 @@
>>>>
>>>>  static unsigned int transition_latency;
>>>>  static unsigned int voltage_tolerance; /* in percentage */
>>>> +static unsigned long safe_frequency;
>>>> +static unsigned long safe_voltage;
>>>>
>>>>  static struct device *cpu_dev;
>>>>  static struct clk *cpu_clk;
>>>> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>>>                 volt_old = regulator_get_voltage(cpu_reg);
>>>>         }
>>>>
>>>> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>>> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
>>>>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
>>>>                  new_freq / 1000, volt ? volt / 1000 : -1);
>>>>
>>>>         /* scaling up?  scale voltage before frequency */
>>>> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
>>>> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
>>>> +                               new_freq >= safe_frequency) {
>>>>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>>>                 if (ret) {
>>>>                         pr_err("failed to scale voltage up: %d\n", ret);
>>>>                         return ret;
>>>>                 }
>>>> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
>>>> +               /*
>>>> +                * the scaled up voltage level for the new_freq is lower
>>>> +                * than the safe voltage level. so set safe_voltage
>>>> +                * as the intermediate voltage level and revert it
>>>> +                * back after the frequency has been changed.
>>>> +                */
>>>> +               ret = regulator_set_voltage_tol(cpu_reg, safe_voltage, tol);
>>>> +               if (ret) {
>>>> +                       pr_err("failed to set safe voltage: %d\n", ret);
>>>> +                       return ret;
>>>> +               }
>>>>         }
>>>>
>>>>         ret = clk_set_rate(cpu_clk, freq_exact);
>>>> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
>>>>         }
>>>>
>>>>         /* scaling down?  scale voltage after frequency */
>>>> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
>>>> +       if (!IS_ERR(cpu_reg) &&
>>>> +                       (new_freq < old_freq || new_freq < safe_frequency)) {
>>>>                 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
>>>>                 if (ret) {
>>>>                         pr_err("failed to scale voltage down: %d\n", ret);
>>>> @@ -116,6 +132,8 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
>>>>
>>>>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>>  {
>>>> +       const struct property *prop;
>>>> +       struct dev_pm_opp *opp;
>>>>         struct device_node *np;
>>>>         int ret;
>>>>
>>>> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>>                 goto out_put_node;
>>>>         }
>>>>
>>>> +       prop = of_find_property(np, "safe-opp", NULL);
>>>> +       if (prop) {
>>>> +               if (prop->value && (prop->length / sizeof(u32)) == 2) {
>>>> +                       const __be32 *val;
>>>> +                       val = prop->value;
>>>> +                       safe_frequency = be32_to_cpup(val++);
>>>> +                       safe_voltage = be32_to_cpup(val);
>>>> +               } else {
>>>> +                       pr_err("invalid safe-opp level specified\n");
>>>> +               }
>>>> +       }
>>>> +
>>>>         of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
>>>>
>>>>         if (of_property_read_u32(np, "clock-latency", &transition_latency))
>>>>                 transition_latency = CPUFREQ_ETERNAL;
>>>>
>>>>         if (!IS_ERR(cpu_reg)) {
>>>> -               struct dev_pm_opp *opp;
>>>>                 unsigned long min_uV, max_uV;
>>>>                 int i;
>>>>
>>>> --
>>>> 1.6.6.rc2
>>>>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-30 12:53         ` Thomas Abraham
@ 2014-01-30 15:09           ` Heiko Stübner
  2014-02-01  4:10             ` Mike Turquette
  2014-02-03 16:06             ` Thomas Abraham
  0 siblings, 2 replies; 51+ messages in thread
From: Heiko Stübner @ 2014-01-30 15:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, 30. January 2014 18:23:44 Thomas Abraham wrote:
> Hi Mike,
> 
> On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org> 
wrote:
> > On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com> 
wrote:
> >> Hi Mike,
> >> 
> >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> 
wrote:
> >>> Quoting Thomas Abraham (2014-01-18 04:10:51)
> >>> 
> > As far as I can tell
> > the remux does not happen because it is necessary to generate the
> > required clock rate, but because we don't want to run the ARM core out
> > of spec for a short time while the PLL relocks. Assuming I have that
> > part of it right, I prefer for the parent mux operation to be a part
> > of the CPUfreq driver's .target callback instead of hidden away in the
> > clock driver.
> 
> The re-parenting is mostly done to keep the ARM CPU clocked while the
> PLL is stopped, reprogrammed and restarted. One of the side effects of
> that is, the clock speed of the temporary parent could be higher then
> what is allowed due to the ARM voltage at the time of re-parenting.
> That is the reason to use the safe voltage.

The Rockchip-SoCs use something similar, so I'm following quite closely what 
Thomas is trying to do here, as similar solution would also solve this issue 
for me.

On some Rockchip-SoCs even stuff like pclk and hclk seems to be sourced from 
the divided armclk, creating additional constraints.

But on the RKs (at least in the upstream sources) the armclk is simply equal 
to the pll output. A divider exists, but is only used to make sure that the 
armclk stays below the original rate when sourced from the temp-parent, like

	if (clk_get_rate(temp_parent) > clk_get_rate(main_parent)
		set_divider(something so that rate(temp) <= rate(main)
	clk_set_parent(...)

Isn't there a similar possiblity on your platform, as it would remove the need 
for the safe-voltage?


In general I also like the approach of hiding the rate-change logic inside 
this composite clock, as the depending clocks can be easily kept in sync. As 
with the Rockchips the depending clocks are different for each of the three 
Cortex-A9 SoCs I looked at, it would be "interesting" if all of this would 
need to be done in a cpufreq driver.


Heiko

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-30 15:09           ` Heiko Stübner
@ 2014-02-01  4:10             ` Mike Turquette
  2014-02-03 16:06               ` Thomas Abraham
  2014-02-05  9:53               ` Heiko Stübner
  2014-02-03 16:06             ` Thomas Abraham
  1 sibling, 2 replies; 51+ messages in thread
From: Mike Turquette @ 2014-02-01  4:10 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Heiko St?bner (2014-01-30 07:09:04)
> On Thursday, 30. January 2014 18:23:44 Thomas Abraham wrote:
> > Hi Mike,
> > 
> > On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org> 
> wrote:
> > > On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com> 
> wrote:
> > >> Hi Mike,
> > >> 
> > >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> 
> wrote:
> > >>> Quoting Thomas Abraham (2014-01-18 04:10:51)
> > >>> 
> > > As far as I can tell
> > > the remux does not happen because it is necessary to generate the
> > > required clock rate, but because we don't want to run the ARM core out
> > > of spec for a short time while the PLL relocks. Assuming I have that
> > > part of it right, I prefer for the parent mux operation to be a part
> > > of the CPUfreq driver's .target callback instead of hidden away in the
> > > clock driver.
> > 
> > The re-parenting is mostly done to keep the ARM CPU clocked while the
> > PLL is stopped, reprogrammed and restarted. One of the side effects of
> > that is, the clock speed of the temporary parent could be higher then
> > what is allowed due to the ARM voltage at the time of re-parenting.
> > That is the reason to use the safe voltage.
> 
> The Rockchip-SoCs use something similar, so I'm following quite closely what 
> Thomas is trying to do here, as similar solution would also solve this issue 
> for me.
> 
> On some Rockchip-SoCs even stuff like pclk and hclk seems to be sourced from 
> the divided armclk, creating additional constraints.
> 
> But on the RKs (at least in the upstream sources) the armclk is simply equal 
> to the pll output. A divider exists, but is only used to make sure that the 
> armclk stays below the original rate when sourced from the temp-parent, like
> 
>         if (clk_get_rate(temp_parent) > clk_get_rate(main_parent)
>                 set_divider(something so that rate(temp) <= rate(main)
>         clk_set_parent(...)
> 
> Isn't there a similar possiblity on your platform, as it would remove the need 
> for the safe-voltage?
> 
> 
> In general I also like the approach of hiding the rate-change logic inside 
> this composite clock, as the depending clocks can be easily kept in sync. As 
> with the Rockchips the depending clocks are different for each of the three 
> Cortex-A9 SoCs I looked at, it would be "interesting" if all of this would 
> need to be done in a cpufreq driver.

I wonder if hiding these details inside of the composite clock
implementation indicates the lack of some needed feature in the clk
core? I've discussed the idea of "coordinated rate changes" before. E.g:

_________________________________________________________
|  clk	|  opp-low	|  opp-mid	|  opp-fast	|
|	|		|		|		|
|pll	| 300000	|  600000	|  600000	|
|	|		|		|		|
|div	| 150000	|  300000	|  600000	|
|	|		|		|		|
|mpu_clk| 150000	|  300000       |  600000	|
|	|		|		|		|
|periph	| 150000	|  150000	|  300000	|
---------------------------------------------------------

A call to clk_set_rate() against any of those clocks will result in all
of their dividers being updated. At the implementation level this might
look something like this extremely simplified pseudocode:

int clk_set_rate(struct clk* clk, unsigned long rate)
{
	/* trap clks that support coordinated rate changes */
	if (clk->ops->coordinate_rate)
		return clk->ops->coordinate_rate(clk->hw, rate);
	...
}

and,

struct coord_rates {
	struct clk_hw *hw;
	struct clk *parent;
	struct clk *rate;
};

and in the clock driver,

#define PLL 0
#define DIV 1
#define MPU 2
#define PER 3

#define NR_OPP 4
#define NR_CLK 4

struct coord_rates my_opps[NR_OPP][NR_CLK]; // populated from DT data

int my_coordinate_rate_callback(struct clk_hw *hw, unsigned long rate)
{
	struct coord_rate **selected_opp;

	for(i = 0; i < NR_OPP; i++) {
		for(j = 0; j < NR_CLK; j++) {
			if (my_opps[i][j]->hw == hw &&
				my_opps[i][j]->rate == rate)
				selected_opp = my_opps[i];
				break;
		}
	}

	/*
	 * order of operations is specific to my hardware and should be
	 * managed by my clock driver, not generic code
	 */

	__clk_set_parent(selected_opp[DIV]->hw, temp_parent);
	__clk_set_rate(selected_opp[PLL]->hw, selected_opp[PLL]->rate);
	__clk_set_parent(selected_opp[DIV]->hw,
				selected_opp[PLL]->hw->clk);
	...

	/*
	 * note that the above could be handled by a switch-case or
	 * something else
	 */
}

Thoughts? Please forgive any gaps in my logic or abuse of C.

I have long thought that something like the above would someday go into
a generic dvfs layer instead of the clock framework, but maybe starting
with the clk framework makes more sense?

Regards,
Mike

> 
> 
> Heiko
> 

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-01-30 15:09           ` Heiko Stübner
  2014-02-01  4:10             ` Mike Turquette
@ 2014-02-03 16:06             ` Thomas Abraham
  1 sibling, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-02-03 16:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 30, 2014 at 8:39 PM, Heiko St?bner <heiko@sntech.de> wrote:
> On Thursday, 30. January 2014 18:23:44 Thomas Abraham wrote:
>> Hi Mike,
>>
>> On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org>
> wrote:
>> > On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com>
> wrote:
>> >> Hi Mike,
>> >>
>> >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org>
> wrote:
>> >>> Quoting Thomas Abraham (2014-01-18 04:10:51)
>> >>>
>> > As far as I can tell
>> > the remux does not happen because it is necessary to generate the
>> > required clock rate, but because we don't want to run the ARM core out
>> > of spec for a short time while the PLL relocks. Assuming I have that
>> > part of it right, I prefer for the parent mux operation to be a part
>> > of the CPUfreq driver's .target callback instead of hidden away in the
>> > clock driver.
>>
>> The re-parenting is mostly done to keep the ARM CPU clocked while the
>> PLL is stopped, reprogrammed and restarted. One of the side effects of
>> that is, the clock speed of the temporary parent could be higher then
>> what is allowed due to the ARM voltage at the time of re-parenting.
>> That is the reason to use the safe voltage.
>
> The Rockchip-SoCs use something similar, so I'm following quite closely what
> Thomas is trying to do here, as similar solution would also solve this issue
> for me.
>
> On some Rockchip-SoCs even stuff like pclk and hclk seems to be sourced from
> the divided armclk, creating additional constraints.
>
> But on the RKs (at least in the upstream sources) the armclk is simply equal
> to the pll output. A divider exists, but is only used to make sure that the
> armclk stays below the original rate when sourced from the temp-parent, like
>
>         if (clk_get_rate(temp_parent) > clk_get_rate(main_parent)
>                 set_divider(something so that rate(temp) <= rate(main)
>         clk_set_parent(...)
>
> Isn't there a similar possiblity on your platform, as it would remove the need
> for the safe-voltage?

Hi Heiko,

Yes, this works too! I have tested this method on Exynos4210,
Exynos4412 and Exynos5250 and it works fine without any need for safe
voltage. This is much better than using safe voltage. Thank you for
suggesting this.

Regards,
Thomas.

>
>
> In general I also like the approach of hiding the rate-change logic inside
> this composite clock, as the depending clocks can be easily kept in sync. As
> with the Rockchips the depending clocks are different for each of the three
> Cortex-A9 SoCs I looked at, it would be "interesting" if all of this would
> need to be done in a cpufreq driver.
>
>
> Heiko
>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-02-01  4:10             ` Mike Turquette
@ 2014-02-03 16:06               ` Thomas Abraham
  2014-02-05  9:53               ` Heiko Stübner
  1 sibling, 0 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-02-03 16:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Feb 1, 2014 at 9:40 AM, Mike Turquette <mturquette@linaro.org> wrote:
> Quoting Heiko St?bner (2014-01-30 07:09:04)
>> On Thursday, 30. January 2014 18:23:44 Thomas Abraham wrote:
>> > Hi Mike,
>> >
>> > On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org>
>> wrote:
>> > > On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com>
>> wrote:
>> > >> Hi Mike,
>> > >>
>> > >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org>
>> wrote:
>> > >>> Quoting Thomas Abraham (2014-01-18 04:10:51)
>> > >>>
>> > > As far as I can tell
>> > > the remux does not happen because it is necessary to generate the
>> > > required clock rate, but because we don't want to run the ARM core out
>> > > of spec for a short time while the PLL relocks. Assuming I have that
>> > > part of it right, I prefer for the parent mux operation to be a part
>> > > of the CPUfreq driver's .target callback instead of hidden away in the
>> > > clock driver.
>> >
>> > The re-parenting is mostly done to keep the ARM CPU clocked while the
>> > PLL is stopped, reprogrammed and restarted. One of the side effects of
>> > that is, the clock speed of the temporary parent could be higher then
>> > what is allowed due to the ARM voltage at the time of re-parenting.
>> > That is the reason to use the safe voltage.
>>
>> The Rockchip-SoCs use something similar, so I'm following quite closely what
>> Thomas is trying to do here, as similar solution would also solve this issue
>> for me.
>>
>> On some Rockchip-SoCs even stuff like pclk and hclk seems to be sourced from
>> the divided armclk, creating additional constraints.
>>
>> But on the RKs (at least in the upstream sources) the armclk is simply equal
>> to the pll output. A divider exists, but is only used to make sure that the
>> armclk stays below the original rate when sourced from the temp-parent, like
>>
>>         if (clk_get_rate(temp_parent) > clk_get_rate(main_parent)
>>                 set_divider(something so that rate(temp) <= rate(main)
>>         clk_set_parent(...)
>>
>> Isn't there a similar possiblity on your platform, as it would remove the need
>> for the safe-voltage?
>>
>>
>> In general I also like the approach of hiding the rate-change logic inside
>> this composite clock, as the depending clocks can be easily kept in sync. As
>> with the Rockchips the depending clocks are different for each of the three
>> Cortex-A9 SoCs I looked at, it would be "interesting" if all of this would
>> need to be done in a cpufreq driver.
>
> I wonder if hiding these details inside of the composite clock
> implementation indicates the lack of some needed feature in the clk
> core? I've discussed the idea of "coordinated rate changes" before. E.g:
>
> _________________________________________________________
> |  clk  |  opp-low      |  opp-mid      |  opp-fast     |
> |       |               |               |               |
> |pll    | 300000        |  600000       |  600000       |
> |       |               |               |               |
> |div    | 150000        |  300000       |  600000       |
> |       |               |               |               |
> |mpu_clk| 150000        |  300000       |  600000       |
> |       |               |               |               |
> |periph | 150000        |  150000       |  300000       |
> ---------------------------------------------------------
>
> A call to clk_set_rate() against any of those clocks will result in all
> of their dividers being updated. At the implementation level this might
> look something like this extremely simplified pseudocode:
>
> int clk_set_rate(struct clk* clk, unsigned long rate)
> {
>         /* trap clks that support coordinated rate changes */
>         if (clk->ops->coordinate_rate)
>                 return clk->ops->coordinate_rate(clk->hw, rate);
>         ...
> }
>
> and,
>
> struct coord_rates {
>         struct clk_hw *hw;
>         struct clk *parent;
>         struct clk *rate;
> };
>
> and in the clock driver,
>
> #define PLL 0
> #define DIV 1
> #define MPU 2
> #define PER 3
>
> #define NR_OPP 4
> #define NR_CLK 4
>
> struct coord_rates my_opps[NR_OPP][NR_CLK]; // populated from DT data
>
> int my_coordinate_rate_callback(struct clk_hw *hw, unsigned long rate)
> {
>         struct coord_rate **selected_opp;
>
>         for(i = 0; i < NR_OPP; i++) {
>                 for(j = 0; j < NR_CLK; j++) {
>                         if (my_opps[i][j]->hw == hw &&
>                                 my_opps[i][j]->rate == rate)
>                                 selected_opp = my_opps[i];
>                                 break;
>                 }
>         }
>
>         /*
>          * order of operations is specific to my hardware and should be
>          * managed by my clock driver, not generic code
>          */
>
>         __clk_set_parent(selected_opp[DIV]->hw, temp_parent);
>         __clk_set_rate(selected_opp[PLL]->hw, selected_opp[PLL]->rate);
>         __clk_set_parent(selected_opp[DIV]->hw,
>                                 selected_opp[PLL]->hw->clk);
>         ...
>
>         /*
>          * note that the above could be handled by a switch-case or
>          * something else
>          */
> }
>
> Thoughts? Please forgive any gaps in my logic or abuse of C.
>
> I have long thought that something like the above would someday go into
> a generic dvfs layer instead of the clock framework, but maybe starting
> with the clk framework makes more sense?

Hi Mike,

Yes, this will be very helpful for atomically controlling the rates of
a group of clocks. This coordinated rate change method can be used
during the armclk rate changes on Samsung platforms.

Thanks,
Thomas.

>
> Regards,
> Mike
>
>>
>>
>> Heiko
>>

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

* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
  2014-02-01  4:10             ` Mike Turquette
  2014-02-03 16:06               ` Thomas Abraham
@ 2014-02-05  9:53               ` Heiko Stübner
  1 sibling, 0 replies; 51+ messages in thread
From: Heiko Stübner @ 2014-02-05  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

Am Freitag, 31. Januar 2014, 20:10:51 schrieb Mike Turquette:
> Quoting Heiko St?bner (2014-01-30 07:09:04)
> 
> > On Thursday, 30. January 2014 18:23:44 Thomas Abraham wrote:
> > > Hi Mike,
> > > 
> > > On Wed, Jan 29, 2014 at 12:17 AM, Mike Turquette <mturquette@linaro.org>
> > 
> > wrote:
> > > > On Mon, Jan 27, 2014 at 9:30 PM, Thomas Abraham <ta.omasab@gmail.com>
> > 
> > wrote:
> > > >> Hi Mike,
> > > >> 
> > > >> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
> > > >> <mturquette@linaro.org>
> > 
> > wrote:
> > > >>> Quoting Thomas Abraham (2014-01-18 04:10:51)
> > > > 
> > > > As far as I can tell
> > > > the remux does not happen because it is necessary to generate the
> > > > required clock rate, but because we don't want to run the ARM core out
> > > > of spec for a short time while the PLL relocks. Assuming I have that
> > > > part of it right, I prefer for the parent mux operation to be a part
> > > > of the CPUfreq driver's .target callback instead of hidden away in the
> > > > clock driver.
> > > 
> > > The re-parenting is mostly done to keep the ARM CPU clocked while the
> > > PLL is stopped, reprogrammed and restarted. One of the side effects of
> > > that is, the clock speed of the temporary parent could be higher then
> > > what is allowed due to the ARM voltage at the time of re-parenting.
> > > That is the reason to use the safe voltage.
> > 
> > The Rockchip-SoCs use something similar, so I'm following quite closely
> > what Thomas is trying to do here, as similar solution would also solve
> > this issue for me.
> > 
> > On some Rockchip-SoCs even stuff like pclk and hclk seems to be sourced
> > from the divided armclk, creating additional constraints.
> > 
> > But on the RKs (at least in the upstream sources) the armclk is simply
> > equal to the pll output. A divider exists, but is only used to make sure
> > that the armclk stays below the original rate when sourced from the
> > temp-parent, like> 
> >         if (clk_get_rate(temp_parent) > clk_get_rate(main_parent)
> >         
> >                 set_divider(something so that rate(temp) <= rate(main)
> >         
> >         clk_set_parent(...)
> > 
> > Isn't there a similar possiblity on your platform, as it would remove the
> > need for the safe-voltage?
> > 
> > 
> > In general I also like the approach of hiding the rate-change logic inside
> > this composite clock, as the depending clocks can be easily kept in sync.
> > As with the Rockchips the depending clocks are different for each of the
> > three Cortex-A9 SoCs I looked at, it would be "interesting" if all of
> > this would need to be done in a cpufreq driver.
> 
> I wonder if hiding these details inside of the composite clock
> implementation indicates the lack of some needed feature in the clk
> core? I've discussed the idea of "coordinated rate changes" before. E.g:
> 
> _________________________________________________________
> 
> |  clk	|  opp-low	|  opp-mid	|  opp-fast	|
> |
> |pll	| 300000	|  600000	|  600000	|
> |
> |div	| 150000	|  300000	|  600000	|
> |
> |mpu_clk| 150000	|  300000       |  600000	|
> |
> |periph	| 150000	|  150000	|  300000	|
> 
> ---------------------------------------------------------
> 
> A call to clk_set_rate() against any of those clocks will result in all
> of their dividers being updated. At the implementation level this might
> look something like this extremely simplified pseudocode:
> 
> int clk_set_rate(struct clk* clk, unsigned long rate)
> {
> 	/* trap clks that support coordinated rate changes */
> 	if (clk->ops->coordinate_rate)
> 		return clk->ops->coordinate_rate(clk->hw, rate);
> 	...
> }
> 
> and,
> 
> struct coord_rates {
> 	struct clk_hw *hw;
> 	struct clk *parent;
> 	struct clk *rate;
> };
> 
> and in the clock driver,
> 
> #define PLL 0
> #define DIV 1
> #define MPU 2
> #define PER 3
> 
> #define NR_OPP 4
> #define NR_CLK 4
> 
> struct coord_rates my_opps[NR_OPP][NR_CLK]; // populated from DT data
> 
> int my_coordinate_rate_callback(struct clk_hw *hw, unsigned long rate)
> {
> 	struct coord_rate **selected_opp;
> 
> 	for(i = 0; i < NR_OPP; i++) {
> 		for(j = 0; j < NR_CLK; j++) {
> 			if (my_opps[i][j]->hw == hw &&
> 				my_opps[i][j]->rate == rate)
> 				selected_opp = my_opps[i];
> 				break;
> 		}
> 	}
> 
> 	/*
> 	 * order of operations is specific to my hardware and should be
> 	 * managed by my clock driver, not generic code
> 	 */
> 
> 	__clk_set_parent(selected_opp[DIV]->hw, temp_parent);
> 	__clk_set_rate(selected_opp[PLL]->hw, selected_opp[PLL]->rate);
> 	__clk_set_parent(selected_opp[DIV]->hw,
> 				selected_opp[PLL]->hw->clk);
> 	...
> 
> 	/*
> 	 * note that the above could be handled by a switch-case or
> 	 * something else
> 	 */
> }
> 
> Thoughts? Please forgive any gaps in my logic or abuse of C.
> 
> I have long thought that something like the above would someday go into
> a generic dvfs layer instead of the clock framework, but maybe starting
> with the clk framework makes more sense?

Similar to Thomas, this looks like the thing I'd need for my core clocks.

Also to me this really looks like something belonging to the clock framework, 
as we at this point really only have some clocks that in all cases need to be 
set together, independent of it beeing embedded in some scaling context or 
something else.


Heiko

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-01-20  8:08   ` Lukasz Majewski
  2014-01-21  8:08     ` Thomas Abraham
@ 2014-02-05 10:21     ` Thomas Abraham
  2014-02-05 11:44       ` Lukasz Majewski
  1 sibling, 1 reply; 51+ messages in thread
From: Thomas Abraham @ 2014-02-05 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Mon, Jan 20, 2014 at 1:38 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched
>> over to use cpufreq-cpu0 driver for cpufreq functionality. So the
>> Exynos specific cpufreq drivers for these platforms can be removed.
>>

<snip>

>> -static unsigned int exynos4x12_volt_table[] = {
>> -     1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
>> 1037500,
>> -     1000000,  987500,  975000,  950000,  925000,  900000,  900000
>> -};
>> -
>> -static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
>> -     {CPUFREQ_BOOST_FREQ, 1500 * 1000},
>
> Here, you are removing BOOST support for Exynos4412, without any code,
> which brings back this functionality in the new code.
>
> I'd propose adding new property to cpus node and during
> operating-points parsing mark the entry at the cpufreq_frequency_table
> accordingly.

I tried doing this as you suggested with [1] but looks like that will
not go through at this point. The other alternative would be to use
exynos specific cpufreq drivers only if multiplatform config is not
selected or use cpufreq-cpu0 if multiplatform config is selected (but
this is not something I would want to do). With this, there are issues
like clock blocks encapsulated within the opaque clock type cannot be
removed since exynos specific cpufreq drivers need it and hence it is
not really a clean solution. The other option is to drop the support
for boost on exynos4x12 for now and reintroduce that when the OPP
bindings have been finalized. Would that be okay? Any other
suggestions will also be helpful.

Thanks,
Thomas.

>
>> -     {L1, 1400 * 1000},
>> -     {L2, 1300 * 1000},
>> -     {L3, 1200 * 1000},
>> -     {L4, 1100 * 1000},
>> -     {L5, 1000 * 1000},
>> -     {L6,  900 * 1000},
>> -     {L7,  800 * 1000},
>> -     {L8,  700 * 1000},
>> -     {L9,  600 * 1000},
>> -     {L10, 500 * 1000},
>> -     {L11, 400 * 1000},
>> -     {L12, 300 * 1000},
>> -     {L13, 200 * 1000},
>> -     {0, CPUFREQ_TABLE_END},
>> -};
>> -
>> -static struct apll_freq *apll_freq_4x12;
>> -
>> -static struct apll_freq apll_freq_4212[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> PCLK_DBG, APLL, CORE2
>> -      * clock divider for COPY, HPM, RESERVED
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
>> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
>> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
>> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
>> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
>> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
>> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
>> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
>> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
>> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
>> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
>> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
>> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
>> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
>> -};
>> -
>> -static struct apll_freq apll_freq_4412[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> PCLK_DBG, APLL, CORE2
>> -      * clock divider for COPY, HPM, CORES
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
>> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
>> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
>> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
>> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
>> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
>> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
>> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
>> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
>> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
>> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
>> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
>> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
>> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
>> -};
>> -
>> -static void exynos4x12_set_clkdiv(unsigned int div_index)
>> -{
>> -     unsigned int tmp;
>> -     unsigned int stat_cpu1;
>> -
>> -     /* Change Divider - CPU0 */
>> -
>> -     tmp = apll_freq_4x12[div_index].clk_div_cpu0;
>> -
>> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
>> -
>> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
>> -             cpu_relax();
>> -
>> -     /* Change Divider - CPU1 */
>> -     tmp = apll_freq_4x12[div_index].clk_div_cpu1;
>> -
>> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
>> -     if (soc_is_exynos4212())
>> -             stat_cpu1 = 0x11;
>> -     else
>> -             stat_cpu1 = 0x111;
>> -
>> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
>> -             cpu_relax();
>> -}
>> -
>> -static void exynos4x12_set_apll(unsigned int index)
>> -{
>> -     unsigned int tmp, freq = apll_freq_4x12[index].freq;
>> -
>> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> -     clk_set_parent(moutcore, mout_mpll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
>> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
>> -             tmp &= 0x7;
>> -     } while (tmp != 0x2);
>> -
>> -     clk_set_rate(mout_apll, freq * 1000);
>> -
>> -     /* MUX_CORE_SEL = APLL */
>> -     clk_set_parent(moutcore, mout_apll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
>> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
>> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
>> -}
>> -
>> -static void exynos4x12_set_frequency(unsigned int old_index,
>> -                               unsigned int new_index)
>> -{
>> -     if (old_index > new_index) {
>> -             exynos4x12_set_clkdiv(new_index);
>> -             exynos4x12_set_apll(new_index);
>> -     } else if (old_index < new_index) {
>> -             exynos4x12_set_apll(new_index);
>> -             exynos4x12_set_clkdiv(new_index);
>> -     }
>> -}
>> -
>> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
>> -{
>> -     unsigned long rate;
>> -
>> -     cpu_clk = clk_get(NULL, "armclk");
>> -     if (IS_ERR(cpu_clk))
>> -             return PTR_ERR(cpu_clk);
>> -
>> -     moutcore = clk_get(NULL, "moutcore");
>> -     if (IS_ERR(moutcore))
>> -             goto err_moutcore;
>> -
>> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> -     if (IS_ERR(mout_mpll))
>> -             goto err_mout_mpll;
>> -
>> -     rate = clk_get_rate(mout_mpll) / 1000;
>> -
>> -     mout_apll = clk_get(NULL, "mout_apll");
>> -     if (IS_ERR(mout_apll))
>> -             goto err_mout_apll;
>> -
>> -     if (soc_is_exynos4212())
>> -             apll_freq_4x12 = apll_freq_4212;
>> -     else
>> -             apll_freq_4x12 = apll_freq_4412;
>> -
>> -     info->mpll_freq_khz = rate;
>> -     /* 800Mhz */
>> -     info->pll_safe_idx = L7;
>> -     info->cpu_clk = cpu_clk;
>> -     info->volt_table = exynos4x12_volt_table;
>> -     info->freq_table = exynos4x12_freq_table;
>> -     info->set_freq = exynos4x12_set_frequency;
>> -
>> -     return 0;
>> -
>> -err_mout_apll:
>> -     clk_put(mout_mpll);
>> -err_mout_mpll:
>> -     clk_put(moutcore);
>> -err_moutcore:
>> -     clk_put(cpu_clk);
>> -
>> -     pr_debug("%s: failed initialization\n", __func__);
>> -     return -EINVAL;
>> -}
>> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
>> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
>> index 5f90b82..0000000
>> --- a/drivers/cpufreq/exynos5250-cpufreq.c
>> +++ /dev/null
>> @@ -1,183 +0,0 @@
>> -/*
>> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
>> - *           http://www.samsung.com
>> - *
>> - * EXYNOS5250 - CPU frequency scaling 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.
>> -*/
>> -
>> -#include <linux/module.h>
>> -#include <linux/kernel.h>
>> -#include <linux/err.h>
>> -#include <linux/clk.h>
>> -#include <linux/io.h>
>> -#include <linux/slab.h>
>> -#include <linux/cpufreq.h>
>> -
>> -#include <mach/map.h>
>> -
>> -#include "exynos-cpufreq.h"
>> -
>> -static struct clk *cpu_clk;
>> -static struct clk *moutcore;
>> -static struct clk *mout_mpll;
>> -static struct clk *mout_apll;
>> -
>> -static unsigned int exynos5250_volt_table[] = {
>> -     1300000, 1250000, 1225000, 1200000, 1150000,
>> -     1125000, 1100000, 1075000, 1050000, 1025000,
>> -     1012500, 1000000,  975000,  950000,  937500,
>> -     925000
>> -};
>> -
>> -static struct cpufreq_frequency_table exynos5250_freq_table[] = {
>> -     {L0, 1700 * 1000},
>> -     {L1, 1600 * 1000},
>> -     {L2, 1500 * 1000},
>> -     {L3, 1400 * 1000},
>> -     {L4, 1300 * 1000},
>> -     {L5, 1200 * 1000},
>> -     {L6, 1100 * 1000},
>> -     {L7, 1000 * 1000},
>> -     {L8,  900 * 1000},
>> -     {L9,  800 * 1000},
>> -     {L10, 700 * 1000},
>> -     {L11, 600 * 1000},
>> -     {L12, 500 * 1000},
>> -     {L13, 400 * 1000},
>> -     {L14, 300 * 1000},
>> -     {L15, 200 * 1000},
>> -     {0, CPUFREQ_TABLE_END},
>> -};
>> -
>> -static struct apll_freq apll_freq_5250[] = {
>> -     /*
>> -      * values:
>> -      * freq
>> -      * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG,
>> APLL, ARM2
>> -      * clock divider for COPY, HPM, RESERVED
>> -      * PLL M, P, S
>> -      */
>> -     APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
>> -     APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
>> -     APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
>> -     APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
>> -     APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
>> -     APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
>> -     APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
>> -     APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
>> -     APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
>> -     APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
>> -     APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
>> -     APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
>> -     APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
>> -     APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
>> -     APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
>> -     APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
>> -};
>> -
>> -static void set_clkdiv(unsigned int div_index)
>> -{
>> -     unsigned int tmp;
>> -
>> -     /* Change Divider - CPU0 */
>> -
>> -     tmp = apll_freq_5250[div_index].clk_div_cpu0;
>> -
>> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
>> -
>> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
>> -             cpu_relax();
>> -
>> -     /* Change Divider - CPU1 */
>> -     tmp = apll_freq_5250[div_index].clk_div_cpu1;
>> -
>> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
>> -
>> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
>> -             cpu_relax();
>> -}
>> -
>> -static void set_apll(unsigned int index)
>> -{
>> -     unsigned int tmp;
>> -     unsigned int freq = apll_freq_5250[index].freq;
>> -
>> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> -     clk_set_parent(moutcore, mout_mpll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
>> -             tmp &= 0x7;
>> -     } while (tmp != 0x2);
>> -
>> -     clk_set_rate(mout_apll, freq * 1000);
>> -
>> -     /* MUX_CORE_SEL = APLL */
>> -     clk_set_parent(moutcore, mout_apll);
>> -
>> -     do {
>> -             cpu_relax();
>> -             tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
>> -             tmp &= (0x7 << 16);
>> -     } while (tmp != (0x1 << 16));
>> -}
>> -
>> -static void exynos5250_set_frequency(unsigned int old_index,
>> -                               unsigned int new_index)
>> -{
>> -     if (old_index > new_index) {
>> -             set_clkdiv(new_index);
>> -             set_apll(new_index);
>> -     } else if (old_index < new_index) {
>> -             set_apll(new_index);
>> -             set_clkdiv(new_index);
>> -     }
>> -}
>> -
>> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
>> -{
>> -     unsigned long rate;
>> -
>> -     cpu_clk = clk_get(NULL, "armclk");
>> -     if (IS_ERR(cpu_clk))
>> -             return PTR_ERR(cpu_clk);
>> -
>> -     moutcore = clk_get(NULL, "mout_cpu");
>> -     if (IS_ERR(moutcore))
>> -             goto err_moutcore;
>> -
>> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> -     if (IS_ERR(mout_mpll))
>> -             goto err_mout_mpll;
>> -
>> -     rate = clk_get_rate(mout_mpll) / 1000;
>> -
>> -     mout_apll = clk_get(NULL, "mout_apll");
>> -     if (IS_ERR(mout_apll))
>> -             goto err_mout_apll;
>> -
>> -     info->mpll_freq_khz = rate;
>> -     /* 800Mhz */
>> -     info->pll_safe_idx = L9;
>> -     info->cpu_clk = cpu_clk;
>> -     info->volt_table = exynos5250_volt_table;
>> -     info->freq_table = exynos5250_freq_table;
>> -     info->set_freq = exynos5250_set_frequency;
>> -
>> -     return 0;
>> -
>> -err_mout_apll:
>> -     clk_put(mout_mpll);
>> -err_mout_mpll:
>> -     clk_put(moutcore);
>> -err_moutcore:
>> -     clk_put(cpu_clk);
>> -
>> -     pr_err("%s: failed initialization\n", __func__);
>> -     return -EINVAL;
>> -}
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-02-05 10:21     ` Thomas Abraham
@ 2014-02-05 11:44       ` Lukasz Majewski
  2014-02-05 12:43         ` Thomas Abraham
  0 siblings, 1 reply; 51+ messages in thread
From: Lukasz Majewski @ 2014-02-05 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

Fist of all, thanks for your patches.

> Hi Lukasz,
> 
> On Mon, Jan 20, 2014 at 1:38 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >>
> >> Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched
> >> over to use cpufreq-cpu0 driver for cpufreq functionality. So the
> >> Exynos specific cpufreq drivers for these platforms can be removed.
> >>
> 
> <snip>
> 
> >> -static unsigned int exynos4x12_volt_table[] = {
> >> -     1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
> >> 1037500,
> >> -     1000000,  987500,  975000,  950000,  925000,  900000,  900000
> >> -};
> >> -
> >> -static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
> >> -     {CPUFREQ_BOOST_FREQ, 1500 * 1000},
> >
> > Here, you are removing BOOST support for Exynos4412, without any
> > code, which brings back this functionality in the new code.
> >
> > I'd propose adding new property to cpus node and during
> > operating-points parsing mark the entry at the
> > cpufreq_frequency_table accordingly.
> 
> I tried doing this as you suggested with [1] but looks like that will
> not go through at this point.

I've read your patches regarding OPP. In my opinion, despite the problem
with further OPP format discussion (which is ongoing and probably will
take some time), there is a palatable solution (presented below).

> The other alternative would be to use
> exynos specific cpufreq drivers only if multiplatform config is not
> selected or use cpufreq-cpu0 if multiplatform config is selected (but
> this is not something I would want to do). With this, there are issues
> like clock blocks encapsulated within the opaque clock type cannot be
> removed since exynos specific cpufreq drivers need it and hence it is
> not really a clean solution. 

It would be a maintenance nightmare. We cannot afford to do such huge
cleanup only partially. The rationale for the whole clean up is to
remove exynosXXXX-cpufreq.c files.

I also share your doubts here. We shall NOT do it this way.

>The other option is to drop the support
> for boost on exynos4x12 for now and reintroduce that when the OPP
> bindings have been finalized. 

So you want to drop the BOOST kernel functionality just because you are
doing clean up and this feature is problematic to provide at new
approach?

> Would that be okay?

It is NOT acceptable. Sorry, but NAK.

> Any other
> suggestions will also be helpful.

For me it would be perfectly fine to see at device tree CPU0 node code
proposed by Nishanth:

operating-points = < Fa Va
	Fb Vb
	Fc Vc
	Fd Vd
	>;  
boost-frequencies = <Fc Fd>;

And then the cpufreq table could be properly modified by marking
relevant frequencies as CPUFREQ_BOOST_FREQ.

> 
> Thanks,
> Thomas.
> 
> >
> >> -     {L1, 1400 * 1000},
> >> -     {L2, 1300 * 1000},
> >> -     {L3, 1200 * 1000},
> >> -     {L4, 1100 * 1000},
> >> -     {L5, 1000 * 1000},
> >> -     {L6,  900 * 1000},
> >> -     {L7,  800 * 1000},
> >> -     {L8,  700 * 1000},
> >> -     {L9,  600 * 1000},
> >> -     {L10, 500 * 1000},
> >> -     {L11, 400 * 1000},
> >> -     {L12, 300 * 1000},
> >> -     {L13, 200 * 1000},
> >> -     {0, CPUFREQ_TABLE_END},
> >> -};
> >> -
> >> -static struct apll_freq *apll_freq_4x12;
> >> -
> >> -static struct apll_freq apll_freq_4212[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> PCLK_DBG, APLL, CORE2
> >> -      * clock divider for COPY, HPM, RESERVED
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
> >> -};
> >> -
> >> -static struct apll_freq apll_freq_4412[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> PCLK_DBG, APLL, CORE2
> >> -      * clock divider for COPY, HPM, CORES
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
> >> -};
> >> -
> >> -static void exynos4x12_set_clkdiv(unsigned int div_index)
> >> -{
> >> -     unsigned int tmp;
> >> -     unsigned int stat_cpu1;
> >> -
> >> -     /* Change Divider - CPU0 */
> >> -
> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu0;
> >> -
> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
> >> -
> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
> >> -             cpu_relax();
> >> -
> >> -     /* Change Divider - CPU1 */
> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu1;
> >> -
> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
> >> -     if (soc_is_exynos4212())
> >> -             stat_cpu1 = 0x11;
> >> -     else
> >> -             stat_cpu1 = 0x111;
> >> -
> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
> >> -             cpu_relax();
> >> -}
> >> -
> >> -static void exynos4x12_set_apll(unsigned int index)
> >> -{
> >> -     unsigned int tmp, freq = apll_freq_4x12[index].freq;
> >> -
> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> -     clk_set_parent(moutcore, mout_mpll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
> >> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
> >> -             tmp &= 0x7;
> >> -     } while (tmp != 0x2);
> >> -
> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> -
> >> -     /* MUX_CORE_SEL = APLL */
> >> -     clk_set_parent(moutcore, mout_apll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
> >> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
> >> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
> >> -}
> >> -
> >> -static void exynos4x12_set_frequency(unsigned int old_index,
> >> -                               unsigned int new_index)
> >> -{
> >> -     if (old_index > new_index) {
> >> -             exynos4x12_set_clkdiv(new_index);
> >> -             exynos4x12_set_apll(new_index);
> >> -     } else if (old_index < new_index) {
> >> -             exynos4x12_set_apll(new_index);
> >> -             exynos4x12_set_clkdiv(new_index);
> >> -     }
> >> -}
> >> -
> >> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
> >> -{
> >> -     unsigned long rate;
> >> -
> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> -     if (IS_ERR(cpu_clk))
> >> -             return PTR_ERR(cpu_clk);
> >> -
> >> -     moutcore = clk_get(NULL, "moutcore");
> >> -     if (IS_ERR(moutcore))
> >> -             goto err_moutcore;
> >> -
> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> -     if (IS_ERR(mout_mpll))
> >> -             goto err_mout_mpll;
> >> -
> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> -
> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> -     if (IS_ERR(mout_apll))
> >> -             goto err_mout_apll;
> >> -
> >> -     if (soc_is_exynos4212())
> >> -             apll_freq_4x12 = apll_freq_4212;
> >> -     else
> >> -             apll_freq_4x12 = apll_freq_4412;
> >> -
> >> -     info->mpll_freq_khz = rate;
> >> -     /* 800Mhz */
> >> -     info->pll_safe_idx = L7;
> >> -     info->cpu_clk = cpu_clk;
> >> -     info->volt_table = exynos4x12_volt_table;
> >> -     info->freq_table = exynos4x12_freq_table;
> >> -     info->set_freq = exynos4x12_set_frequency;
> >> -
> >> -     return 0;
> >> -
> >> -err_mout_apll:
> >> -     clk_put(mout_mpll);
> >> -err_mout_mpll:
> >> -     clk_put(moutcore);
> >> -err_moutcore:
> >> -     clk_put(cpu_clk);
> >> -
> >> -     pr_debug("%s: failed initialization\n", __func__);
> >> -     return -EINVAL;
> >> -}
> >> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
> >> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
> >> index 5f90b82..0000000
> >> --- a/drivers/cpufreq/exynos5250-cpufreq.c
> >> +++ /dev/null
> >> @@ -1,183 +0,0 @@
> >> -/*
> >> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
> >> - *           http://www.samsung.com
> >> - *
> >> - * EXYNOS5250 - CPU frequency scaling 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.
> >> -*/
> >> -
> >> -#include <linux/module.h>
> >> -#include <linux/kernel.h>
> >> -#include <linux/err.h>
> >> -#include <linux/clk.h>
> >> -#include <linux/io.h>
> >> -#include <linux/slab.h>
> >> -#include <linux/cpufreq.h>
> >> -
> >> -#include <mach/map.h>
> >> -
> >> -#include "exynos-cpufreq.h"
> >> -
> >> -static struct clk *cpu_clk;
> >> -static struct clk *moutcore;
> >> -static struct clk *mout_mpll;
> >> -static struct clk *mout_apll;
> >> -
> >> -static unsigned int exynos5250_volt_table[] = {
> >> -     1300000, 1250000, 1225000, 1200000, 1150000,
> >> -     1125000, 1100000, 1075000, 1050000, 1025000,
> >> -     1012500, 1000000,  975000,  950000,  937500,
> >> -     925000
> >> -};
> >> -
> >> -static struct cpufreq_frequency_table exynos5250_freq_table[] = {
> >> -     {L0, 1700 * 1000},
> >> -     {L1, 1600 * 1000},
> >> -     {L2, 1500 * 1000},
> >> -     {L3, 1400 * 1000},
> >> -     {L4, 1300 * 1000},
> >> -     {L5, 1200 * 1000},
> >> -     {L6, 1100 * 1000},
> >> -     {L7, 1000 * 1000},
> >> -     {L8,  900 * 1000},
> >> -     {L9,  800 * 1000},
> >> -     {L10, 700 * 1000},
> >> -     {L11, 600 * 1000},
> >> -     {L12, 500 * 1000},
> >> -     {L13, 400 * 1000},
> >> -     {L14, 300 * 1000},
> >> -     {L15, 200 * 1000},
> >> -     {0, CPUFREQ_TABLE_END},
> >> -};
> >> -
> >> -static struct apll_freq apll_freq_5250[] = {
> >> -     /*
> >> -      * values:
> >> -      * freq
> >> -      * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG,
> >> APLL, ARM2
> >> -      * clock divider for COPY, HPM, RESERVED
> >> -      * PLL M, P, S
> >> -      */
> >> -     APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
> >> -     APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
> >> -     APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
> >> -     APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
> >> -     APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
> >> -     APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
> >> -     APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
> >> -     APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
> >> -     APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
> >> -     APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
> >> -     APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
> >> -     APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
> >> -     APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
> >> -     APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
> >> -     APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
> >> -     APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
> >> -};
> >> -
> >> -static void set_clkdiv(unsigned int div_index)
> >> -{
> >> -     unsigned int tmp;
> >> -
> >> -     /* Change Divider - CPU0 */
> >> -
> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu0;
> >> -
> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
> >> -
> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
> >> -             cpu_relax();
> >> -
> >> -     /* Change Divider - CPU1 */
> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu1;
> >> -
> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
> >> -
> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
> >> -             cpu_relax();
> >> -}
> >> -
> >> -static void set_apll(unsigned int index)
> >> -{
> >> -     unsigned int tmp;
> >> -     unsigned int freq = apll_freq_5250[index].freq;
> >> -
> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> -     clk_set_parent(moutcore, mout_mpll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
> >> -             tmp &= 0x7;
> >> -     } while (tmp != 0x2);
> >> -
> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> -
> >> -     /* MUX_CORE_SEL = APLL */
> >> -     clk_set_parent(moutcore, mout_apll);
> >> -
> >> -     do {
> >> -             cpu_relax();
> >> -             tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
> >> -             tmp &= (0x7 << 16);
> >> -     } while (tmp != (0x1 << 16));
> >> -}
> >> -
> >> -static void exynos5250_set_frequency(unsigned int old_index,
> >> -                               unsigned int new_index)
> >> -{
> >> -     if (old_index > new_index) {
> >> -             set_clkdiv(new_index);
> >> -             set_apll(new_index);
> >> -     } else if (old_index < new_index) {
> >> -             set_apll(new_index);
> >> -             set_clkdiv(new_index);
> >> -     }
> >> -}
> >> -
> >> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
> >> -{
> >> -     unsigned long rate;
> >> -
> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> -     if (IS_ERR(cpu_clk))
> >> -             return PTR_ERR(cpu_clk);
> >> -
> >> -     moutcore = clk_get(NULL, "mout_cpu");
> >> -     if (IS_ERR(moutcore))
> >> -             goto err_moutcore;
> >> -
> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> -     if (IS_ERR(mout_mpll))
> >> -             goto err_mout_mpll;
> >> -
> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> -
> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> -     if (IS_ERR(mout_apll))
> >> -             goto err_mout_apll;
> >> -
> >> -     info->mpll_freq_khz = rate;
> >> -     /* 800Mhz */
> >> -     info->pll_safe_idx = L9;
> >> -     info->cpu_clk = cpu_clk;
> >> -     info->volt_table = exynos5250_volt_table;
> >> -     info->freq_table = exynos5250_freq_table;
> >> -     info->set_freq = exynos5250_set_frequency;
> >> -
> >> -     return 0;
> >> -
> >> -err_mout_apll:
> >> -     clk_put(mout_mpll);
> >> -err_mout_mpll:
> >> -     clk_put(moutcore);
> >> -err_moutcore:
> >> -     clk_put(cpu_clk);
> >> -
> >> -     pr_err("%s: failed initialization\n", __func__);
> >> -     return -EINVAL;
> >> -}
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> --
> To unsubscribe from this list: send the line "unsubscribe cpufreq" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-02-05 11:44       ` Lukasz Majewski
@ 2014-02-05 12:43         ` Thomas Abraham
  2014-02-05 13:15           ` Lukasz Majewski
  2014-02-05 13:36           ` Nishanth Menon
  0 siblings, 2 replies; 51+ messages in thread
From: Thomas Abraham @ 2014-02-05 12:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lukasz,

On Wed, Feb 5, 2014 at 5:14 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Thomas,
>
> Fist of all, thanks for your patches.
>
>> Hi Lukasz,
>>
>> On Mon, Jan 20, 2014 at 1:38 PM, Lukasz Majewski
>> <l.majewski@samsung.com> wrote:
>> > Hi Thomas,
>> >
>> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >>
>> >> Exynos4210, Exynos4x12 and Exynos5250 based platforms have switched
>> >> over to use cpufreq-cpu0 driver for cpufreq functionality. So the
>> >> Exynos specific cpufreq drivers for these platforms can be removed.
>> >>
>>
>> <snip>
>>
>> >> -static unsigned int exynos4x12_volt_table[] = {
>> >> -     1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
>> >> 1037500,
>> >> -     1000000,  987500,  975000,  950000,  925000,  900000,  900000
>> >> -};
>> >> -
>> >> -static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
>> >> -     {CPUFREQ_BOOST_FREQ, 1500 * 1000},
>> >
>> > Here, you are removing BOOST support for Exynos4412, without any
>> > code, which brings back this functionality in the new code.
>> >
>> > I'd propose adding new property to cpus node and during
>> > operating-points parsing mark the entry at the
>> > cpufreq_frequency_table accordingly.
>>
>> I tried doing this as you suggested with [1] but looks like that will
>> not go through at this point.
>
> I've read your patches regarding OPP. In my opinion, despite the problem
> with further OPP format discussion (which is ongoing and probably will
> take some time), there is a palatable solution (presented below).
>
>> The other alternative would be to use
>> exynos specific cpufreq drivers only if multiplatform config is not
>> selected or use cpufreq-cpu0 if multiplatform config is selected (but
>> this is not something I would want to do). With this, there are issues
>> like clock blocks encapsulated within the opaque clock type cannot be
>> removed since exynos specific cpufreq drivers need it and hence it is
>> not really a clean solution.
>
> It would be a maintenance nightmare. We cannot afford to do such huge
> cleanup only partially. The rationale for the whole clean up is to
> remove exynosXXXX-cpufreq.c files.
>
> I also share your doubts here. We shall NOT do it this way.
>
>>The other option is to drop the support
>> for boost on exynos4x12 for now and reintroduce that when the OPP
>> bindings have been finalized.
>
> So you want to drop the BOOST kernel functionality just because you are
> doing clean up and this feature is problematic to provide at new
> approach?
>
>> Would that be okay?
>
> It is NOT acceptable. Sorry, but NAK.
>
>> Any other
>> suggestions will also be helpful.
>
> For me it would be perfectly fine to see at device tree CPU0 node code
> proposed by Nishanth:
>
> operating-points = < Fa Va
>         Fb Vb
>         Fc Vc
>         Fd Vd
>         >;
> boost-frequencies = <Fc Fd>;
>
> And then the cpufreq table could be properly modified by marking
> relevant frequencies as CPUFREQ_BOOST_FREQ.

Okay, thanks. Initially it looked like adding boost frequencies into
operating-modes would convolute it but I guess I was wrong. So I will
add support for looking up "boost-frequencies" property in
dev_pm_opp_init_cpufreq_table function and mark the frequencies listed
in this binding as CPUFREQ_BOOST_FREQ.

Thanks,
Thomas.

>
>>
>> Thanks,
>> Thomas.
>>
>> >
>> >> -     {L1, 1400 * 1000},
>> >> -     {L2, 1300 * 1000},
>> >> -     {L3, 1200 * 1000},
>> >> -     {L4, 1100 * 1000},
>> >> -     {L5, 1000 * 1000},
>> >> -     {L6,  900 * 1000},
>> >> -     {L7,  800 * 1000},
>> >> -     {L8,  700 * 1000},
>> >> -     {L9,  600 * 1000},
>> >> -     {L10, 500 * 1000},
>> >> -     {L11, 400 * 1000},
>> >> -     {L12, 300 * 1000},
>> >> -     {L13, 200 * 1000},
>> >> -     {0, CPUFREQ_TABLE_END},
>> >> -};
>> >> -
>> >> -static struct apll_freq *apll_freq_4x12;
>> >> -
>> >> -static struct apll_freq apll_freq_4212[] = {
>> >> -     /*
>> >> -      * values:
>> >> -      * freq
>> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> >> PCLK_DBG, APLL, CORE2
>> >> -      * clock divider for COPY, HPM, RESERVED
>> >> -      * PLL M, P, S
>> >> -      */
>> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
>> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
>> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
>> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
>> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
>> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
>> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
>> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
>> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
>> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
>> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
>> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
>> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
>> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
>> >> -};
>> >> -
>> >> -static struct apll_freq apll_freq_4412[] = {
>> >> -     /*
>> >> -      * values:
>> >> -      * freq
>> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
>> >> PCLK_DBG, APLL, CORE2
>> >> -      * clock divider for COPY, HPM, CORES
>> >> -      * PLL M, P, S
>> >> -      */
>> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
>> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
>> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
>> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
>> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
>> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
>> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
>> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
>> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
>> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
>> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
>> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
>> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
>> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
>> >> -};
>> >> -
>> >> -static void exynos4x12_set_clkdiv(unsigned int div_index)
>> >> -{
>> >> -     unsigned int tmp;
>> >> -     unsigned int stat_cpu1;
>> >> -
>> >> -     /* Change Divider - CPU0 */
>> >> -
>> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu0;
>> >> -
>> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
>> >> -
>> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
>> >> -             cpu_relax();
>> >> -
>> >> -     /* Change Divider - CPU1 */
>> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu1;
>> >> -
>> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
>> >> -     if (soc_is_exynos4212())
>> >> -             stat_cpu1 = 0x11;
>> >> -     else
>> >> -             stat_cpu1 = 0x111;
>> >> -
>> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
>> >> -             cpu_relax();
>> >> -}
>> >> -
>> >> -static void exynos4x12_set_apll(unsigned int index)
>> >> -{
>> >> -     unsigned int tmp, freq = apll_freq_4x12[index].freq;
>> >> -
>> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> >> -     clk_set_parent(moutcore, mout_mpll);
>> >> -
>> >> -     do {
>> >> -             cpu_relax();
>> >> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
>> >> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
>> >> -             tmp &= 0x7;
>> >> -     } while (tmp != 0x2);
>> >> -
>> >> -     clk_set_rate(mout_apll, freq * 1000);
>> >> -
>> >> -     /* MUX_CORE_SEL = APLL */
>> >> -     clk_set_parent(moutcore, mout_apll);
>> >> -
>> >> -     do {
>> >> -             cpu_relax();
>> >> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
>> >> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
>> >> -     } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
>> >> -}
>> >> -
>> >> -static void exynos4x12_set_frequency(unsigned int old_index,
>> >> -                               unsigned int new_index)
>> >> -{
>> >> -     if (old_index > new_index) {
>> >> -             exynos4x12_set_clkdiv(new_index);
>> >> -             exynos4x12_set_apll(new_index);
>> >> -     } else if (old_index < new_index) {
>> >> -             exynos4x12_set_apll(new_index);
>> >> -             exynos4x12_set_clkdiv(new_index);
>> >> -     }
>> >> -}
>> >> -
>> >> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
>> >> -{
>> >> -     unsigned long rate;
>> >> -
>> >> -     cpu_clk = clk_get(NULL, "armclk");
>> >> -     if (IS_ERR(cpu_clk))
>> >> -             return PTR_ERR(cpu_clk);
>> >> -
>> >> -     moutcore = clk_get(NULL, "moutcore");
>> >> -     if (IS_ERR(moutcore))
>> >> -             goto err_moutcore;
>> >> -
>> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> >> -     if (IS_ERR(mout_mpll))
>> >> -             goto err_mout_mpll;
>> >> -
>> >> -     rate = clk_get_rate(mout_mpll) / 1000;
>> >> -
>> >> -     mout_apll = clk_get(NULL, "mout_apll");
>> >> -     if (IS_ERR(mout_apll))
>> >> -             goto err_mout_apll;
>> >> -
>> >> -     if (soc_is_exynos4212())
>> >> -             apll_freq_4x12 = apll_freq_4212;
>> >> -     else
>> >> -             apll_freq_4x12 = apll_freq_4412;
>> >> -
>> >> -     info->mpll_freq_khz = rate;
>> >> -     /* 800Mhz */
>> >> -     info->pll_safe_idx = L7;
>> >> -     info->cpu_clk = cpu_clk;
>> >> -     info->volt_table = exynos4x12_volt_table;
>> >> -     info->freq_table = exynos4x12_freq_table;
>> >> -     info->set_freq = exynos4x12_set_frequency;
>> >> -
>> >> -     return 0;
>> >> -
>> >> -err_mout_apll:
>> >> -     clk_put(mout_mpll);
>> >> -err_mout_mpll:
>> >> -     clk_put(moutcore);
>> >> -err_moutcore:
>> >> -     clk_put(cpu_clk);
>> >> -
>> >> -     pr_debug("%s: failed initialization\n", __func__);
>> >> -     return -EINVAL;
>> >> -}
>> >> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
>> >> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
>> >> index 5f90b82..0000000
>> >> --- a/drivers/cpufreq/exynos5250-cpufreq.c
>> >> +++ /dev/null
>> >> @@ -1,183 +0,0 @@
>> >> -/*
>> >> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
>> >> - *           http://www.samsung.com
>> >> - *
>> >> - * EXYNOS5250 - CPU frequency scaling 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.
>> >> -*/
>> >> -
>> >> -#include <linux/module.h>
>> >> -#include <linux/kernel.h>
>> >> -#include <linux/err.h>
>> >> -#include <linux/clk.h>
>> >> -#include <linux/io.h>
>> >> -#include <linux/slab.h>
>> >> -#include <linux/cpufreq.h>
>> >> -
>> >> -#include <mach/map.h>
>> >> -
>> >> -#include "exynos-cpufreq.h"
>> >> -
>> >> -static struct clk *cpu_clk;
>> >> -static struct clk *moutcore;
>> >> -static struct clk *mout_mpll;
>> >> -static struct clk *mout_apll;
>> >> -
>> >> -static unsigned int exynos5250_volt_table[] = {
>> >> -     1300000, 1250000, 1225000, 1200000, 1150000,
>> >> -     1125000, 1100000, 1075000, 1050000, 1025000,
>> >> -     1012500, 1000000,  975000,  950000,  937500,
>> >> -     925000
>> >> -};
>> >> -
>> >> -static struct cpufreq_frequency_table exynos5250_freq_table[] = {
>> >> -     {L0, 1700 * 1000},
>> >> -     {L1, 1600 * 1000},
>> >> -     {L2, 1500 * 1000},
>> >> -     {L3, 1400 * 1000},
>> >> -     {L4, 1300 * 1000},
>> >> -     {L5, 1200 * 1000},
>> >> -     {L6, 1100 * 1000},
>> >> -     {L7, 1000 * 1000},
>> >> -     {L8,  900 * 1000},
>> >> -     {L9,  800 * 1000},
>> >> -     {L10, 700 * 1000},
>> >> -     {L11, 600 * 1000},
>> >> -     {L12, 500 * 1000},
>> >> -     {L13, 400 * 1000},
>> >> -     {L14, 300 * 1000},
>> >> -     {L15, 200 * 1000},
>> >> -     {0, CPUFREQ_TABLE_END},
>> >> -};
>> >> -
>> >> -static struct apll_freq apll_freq_5250[] = {
>> >> -     /*
>> >> -      * values:
>> >> -      * freq
>> >> -      * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG,
>> >> APLL, ARM2
>> >> -      * clock divider for COPY, HPM, RESERVED
>> >> -      * PLL M, P, S
>> >> -      */
>> >> -     APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
>> >> -     APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
>> >> -     APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
>> >> -     APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
>> >> -     APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
>> >> -     APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
>> >> -     APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
>> >> -     APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
>> >> -     APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
>> >> -     APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
>> >> -     APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
>> >> -     APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
>> >> -     APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
>> >> -     APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
>> >> -     APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
>> >> -     APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
>> >> -};
>> >> -
>> >> -static void set_clkdiv(unsigned int div_index)
>> >> -{
>> >> -     unsigned int tmp;
>> >> -
>> >> -     /* Change Divider - CPU0 */
>> >> -
>> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu0;
>> >> -
>> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
>> >> -
>> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
>> >> -             cpu_relax();
>> >> -
>> >> -     /* Change Divider - CPU1 */
>> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu1;
>> >> -
>> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
>> >> -
>> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
>> >> -             cpu_relax();
>> >> -}
>> >> -
>> >> -static void set_apll(unsigned int index)
>> >> -{
>> >> -     unsigned int tmp;
>> >> -     unsigned int freq = apll_freq_5250[index].freq;
>> >> -
>> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
>> >> -     clk_set_parent(moutcore, mout_mpll);
>> >> -
>> >> -     do {
>> >> -             cpu_relax();
>> >> -             tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
>> >> -             tmp &= 0x7;
>> >> -     } while (tmp != 0x2);
>> >> -
>> >> -     clk_set_rate(mout_apll, freq * 1000);
>> >> -
>> >> -     /* MUX_CORE_SEL = APLL */
>> >> -     clk_set_parent(moutcore, mout_apll);
>> >> -
>> >> -     do {
>> >> -             cpu_relax();
>> >> -             tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
>> >> -             tmp &= (0x7 << 16);
>> >> -     } while (tmp != (0x1 << 16));
>> >> -}
>> >> -
>> >> -static void exynos5250_set_frequency(unsigned int old_index,
>> >> -                               unsigned int new_index)
>> >> -{
>> >> -     if (old_index > new_index) {
>> >> -             set_clkdiv(new_index);
>> >> -             set_apll(new_index);
>> >> -     } else if (old_index < new_index) {
>> >> -             set_apll(new_index);
>> >> -             set_clkdiv(new_index);
>> >> -     }
>> >> -}
>> >> -
>> >> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
>> >> -{
>> >> -     unsigned long rate;
>> >> -
>> >> -     cpu_clk = clk_get(NULL, "armclk");
>> >> -     if (IS_ERR(cpu_clk))
>> >> -             return PTR_ERR(cpu_clk);
>> >> -
>> >> -     moutcore = clk_get(NULL, "mout_cpu");
>> >> -     if (IS_ERR(moutcore))
>> >> -             goto err_moutcore;
>> >> -
>> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
>> >> -     if (IS_ERR(mout_mpll))
>> >> -             goto err_mout_mpll;
>> >> -
>> >> -     rate = clk_get_rate(mout_mpll) / 1000;
>> >> -
>> >> -     mout_apll = clk_get(NULL, "mout_apll");
>> >> -     if (IS_ERR(mout_apll))
>> >> -             goto err_mout_apll;
>> >> -
>> >> -     info->mpll_freq_khz = rate;
>> >> -     /* 800Mhz */
>> >> -     info->pll_safe_idx = L9;
>> >> -     info->cpu_clk = cpu_clk;
>> >> -     info->volt_table = exynos5250_volt_table;
>> >> -     info->freq_table = exynos5250_freq_table;
>> >> -     info->set_freq = exynos5250_set_frequency;
>> >> -
>> >> -     return 0;
>> >> -
>> >> -err_mout_apll:
>> >> -     clk_put(mout_mpll);
>> >> -err_mout_mpll:
>> >> -     clk_put(moutcore);
>> >> -err_moutcore:
>> >> -     clk_put(cpu_clk);
>> >> -
>> >> -     pr_err("%s: failed initialization\n", __func__);
>> >> -     return -EINVAL;
>> >> -}
>> >
>> >
>> >
>> > --
>> > Best regards,
>> >
>> > Lukasz Majewski
>> >
>> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
>> --
>> To unsubscribe from this list: send the line "unsubscribe cpufreq" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
>
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-02-05 12:43         ` Thomas Abraham
@ 2014-02-05 13:15           ` Lukasz Majewski
  2014-02-05 13:36           ` Nishanth Menon
  1 sibling, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-02-05 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> Hi Lukasz,
> 
> On Wed, Feb 5, 2014 at 5:14 PM, Lukasz Majewski
> <l.majewski@samsung.com> wrote:
> > Hi Thomas,
> >
> > Fist of all, thanks for your patches.
> >
> >> Hi Lukasz,
> >>
> >> On Mon, Jan 20, 2014 at 1:38 PM, Lukasz Majewski
> >> <l.majewski@samsung.com> wrote:
> >> > Hi Thomas,
> >> >
> >> >> From: Thomas Abraham <thomas.ab@samsung.com>
> >> >>
> >> >> Exynos4210, Exynos4x12 and Exynos5250 based platforms have
> >> >> switched over to use cpufreq-cpu0 driver for cpufreq
> >> >> functionality. So the Exynos specific cpufreq drivers for these
> >> >> platforms can be removed.
> >> >>
> >>
> >> <snip>
> >>
> >> >> -static unsigned int exynos4x12_volt_table[] = {
> >> >> -     1350000, 1287500, 1250000, 1187500, 1137500, 1087500,
> >> >> 1037500,
> >> >> -     1000000,  987500,  975000,  950000,  925000,  900000,
> >> >> 900000 -};
> >> >> -
> >> >> -static struct cpufreq_frequency_table exynos4x12_freq_table[]
> >> >> = {
> >> >> -     {CPUFREQ_BOOST_FREQ, 1500 * 1000},
> >> >
> >> > Here, you are removing BOOST support for Exynos4412, without any
> >> > code, which brings back this functionality in the new code.
> >> >
> >> > I'd propose adding new property to cpus node and during
> >> > operating-points parsing mark the entry at the
> >> > cpufreq_frequency_table accordingly.
> >>
> >> I tried doing this as you suggested with [1] but looks like that
> >> will not go through at this point.
> >
> > I've read your patches regarding OPP. In my opinion, despite the
> > problem with further OPP format discussion (which is ongoing and
> > probably will take some time), there is a palatable solution
> > (presented below).
> >
> >> The other alternative would be to use
> >> exynos specific cpufreq drivers only if multiplatform config is not
> >> selected or use cpufreq-cpu0 if multiplatform config is selected
> >> (but this is not something I would want to do). With this, there
> >> are issues like clock blocks encapsulated within the opaque clock
> >> type cannot be removed since exynos specific cpufreq drivers need
> >> it and hence it is not really a clean solution.
> >
> > It would be a maintenance nightmare. We cannot afford to do such
> > huge cleanup only partially. The rationale for the whole clean up
> > is to remove exynosXXXX-cpufreq.c files.
> >
> > I also share your doubts here. We shall NOT do it this way.
> >
> >>The other option is to drop the support
> >> for boost on exynos4x12 for now and reintroduce that when the OPP
> >> bindings have been finalized.
> >
> > So you want to drop the BOOST kernel functionality just because you
> > are doing clean up and this feature is problematic to provide at new
> > approach?
> >
> >> Would that be okay?
> >
> > It is NOT acceptable. Sorry, but NAK.
> >
> >> Any other
> >> suggestions will also be helpful.
> >
> > For me it would be perfectly fine to see at device tree CPU0 node
> > code proposed by Nishanth:
> >
> > operating-points = < Fa Va
> >         Fb Vb
> >         Fc Vc
> >         Fd Vd
> >         >;
> > boost-frequencies = <Fc Fd>;
> >
> > And then the cpufreq table could be properly modified by marking
> > relevant frequencies as CPUFREQ_BOOST_FREQ.
> 
> Okay, thanks. Initially it looked like adding boost frequencies into
> operating-modes would convolute it but I guess I was wrong. So I will
> add support for looking up "boost-frequencies" property in
> dev_pm_opp_init_cpufreq_table function and mark the frequencies listed
> in this binding as CPUFREQ_BOOST_FREQ.

That would be great. I'm looking forward for patches :-). 

Thanks.

> 
> Thanks,
> Thomas.
> 
> >
> >>
> >> Thanks,
> >> Thomas.
> >>
> >> >
> >> >> -     {L1, 1400 * 1000},
> >> >> -     {L2, 1300 * 1000},
> >> >> -     {L3, 1200 * 1000},
> >> >> -     {L4, 1100 * 1000},
> >> >> -     {L5, 1000 * 1000},
> >> >> -     {L6,  900 * 1000},
> >> >> -     {L7,  800 * 1000},
> >> >> -     {L8,  700 * 1000},
> >> >> -     {L9,  600 * 1000},
> >> >> -     {L10, 500 * 1000},
> >> >> -     {L11, 400 * 1000},
> >> >> -     {L12, 300 * 1000},
> >> >> -     {L13, 200 * 1000},
> >> >> -     {0, CPUFREQ_TABLE_END},
> >> >> -};
> >> >> -
> >> >> -static struct apll_freq *apll_freq_4x12;
> >> >> -
> >> >> -static struct apll_freq apll_freq_4212[] = {
> >> >> -     /*
> >> >> -      * values:
> >> >> -      * freq
> >> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> >> PCLK_DBG, APLL, CORE2
> >> >> -      * clock divider for COPY, HPM, RESERVED
> >> >> -      * PLL M, P, S
> >> >> -      */
> >> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4,
> >> >> 1),
> >> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4,
> >> >> 2),
> >> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3,
> >> >> 2), -};
> >> >> -
> >> >> -static struct apll_freq apll_freq_4412[] = {
> >> >> -     /*
> >> >> -      * values:
> >> >> -      * freq
> >> >> -      * clock divider for CORE, COREM0, COREM1, PERIPH, ATB,
> >> >> PCLK_DBG, APLL, CORE2
> >> >> -      * clock divider for COPY, HPM, CORES
> >> >> -      * PLL M, P, S
> >> >> -      */
> >> >> -     APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4,
> >> >> 1),
> >> >> -     APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4,
> >> >> 2),
> >> >> -     APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3,
> >> >> 2), -};
> >> >> -
> >> >> -static void exynos4x12_set_clkdiv(unsigned int div_index)
> >> >> -{
> >> >> -     unsigned int tmp;
> >> >> -     unsigned int stat_cpu1;
> >> >> -
> >> >> -     /* Change Divider - CPU0 */
> >> >> -
> >> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu0;
> >> >> -
> >> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
> >> >> -
> >> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
> >> >> -             cpu_relax();
> >> >> -
> >> >> -     /* Change Divider - CPU1 */
> >> >> -     tmp = apll_freq_4x12[div_index].clk_div_cpu1;
> >> >> -
> >> >> -     __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
> >> >> -     if (soc_is_exynos4212())
> >> >> -             stat_cpu1 = 0x11;
> >> >> -     else
> >> >> -             stat_cpu1 = 0x111;
> >> >> -
> >> >> -     while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
> >> >> -             cpu_relax();
> >> >> -}
> >> >> -
> >> >> -static void exynos4x12_set_apll(unsigned int index)
> >> >> -{
> >> >> -     unsigned int tmp, freq = apll_freq_4x12[index].freq;
> >> >> -
> >> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> >> -     clk_set_parent(moutcore, mout_mpll);
> >> >> -
> >> >> -     do {
> >> >> -             cpu_relax();
> >> >> -             tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
> >> >> -                     >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
> >> >> -             tmp &= 0x7;
> >> >> -     } while (tmp != 0x2);
> >> >> -
> >> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> >> -
> >> >> -     /* MUX_CORE_SEL = APLL */
> >> >> -     clk_set_parent(moutcore, mout_apll);
> >> >> -
> >> >> -     do {
> >> >> -             cpu_relax();
> >> >> -             tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
> >> >> -             tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
> >> >> -     } while (tmp != (0x1 <<
> >> >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)); -}
> >> >> -
> >> >> -static void exynos4x12_set_frequency(unsigned int old_index,
> >> >> -                               unsigned int new_index)
> >> >> -{
> >> >> -     if (old_index > new_index) {
> >> >> -             exynos4x12_set_clkdiv(new_index);
> >> >> -             exynos4x12_set_apll(new_index);
> >> >> -     } else if (old_index < new_index) {
> >> >> -             exynos4x12_set_apll(new_index);
> >> >> -             exynos4x12_set_clkdiv(new_index);
> >> >> -     }
> >> >> -}
> >> >> -
> >> >> -int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
> >> >> -{
> >> >> -     unsigned long rate;
> >> >> -
> >> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> >> -     if (IS_ERR(cpu_clk))
> >> >> -             return PTR_ERR(cpu_clk);
> >> >> -
> >> >> -     moutcore = clk_get(NULL, "moutcore");
> >> >> -     if (IS_ERR(moutcore))
> >> >> -             goto err_moutcore;
> >> >> -
> >> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> >> -     if (IS_ERR(mout_mpll))
> >> >> -             goto err_mout_mpll;
> >> >> -
> >> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> >> -
> >> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> >> -     if (IS_ERR(mout_apll))
> >> >> -             goto err_mout_apll;
> >> >> -
> >> >> -     if (soc_is_exynos4212())
> >> >> -             apll_freq_4x12 = apll_freq_4212;
> >> >> -     else
> >> >> -             apll_freq_4x12 = apll_freq_4412;
> >> >> -
> >> >> -     info->mpll_freq_khz = rate;
> >> >> -     /* 800Mhz */
> >> >> -     info->pll_safe_idx = L7;
> >> >> -     info->cpu_clk = cpu_clk;
> >> >> -     info->volt_table = exynos4x12_volt_table;
> >> >> -     info->freq_table = exynos4x12_freq_table;
> >> >> -     info->set_freq = exynos4x12_set_frequency;
> >> >> -
> >> >> -     return 0;
> >> >> -
> >> >> -err_mout_apll:
> >> >> -     clk_put(mout_mpll);
> >> >> -err_mout_mpll:
> >> >> -     clk_put(moutcore);
> >> >> -err_moutcore:
> >> >> -     clk_put(cpu_clk);
> >> >> -
> >> >> -     pr_debug("%s: failed initialization\n", __func__);
> >> >> -     return -EINVAL;
> >> >> -}
> >> >> diff --git a/drivers/cpufreq/exynos5250-cpufreq.c
> >> >> b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644
> >> >> index 5f90b82..0000000
> >> >> --- a/drivers/cpufreq/exynos5250-cpufreq.c
> >> >> +++ /dev/null
> >> >> @@ -1,183 +0,0 @@
> >> >> -/*
> >> >> - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
> >> >> - *           http://www.samsung.com
> >> >> - *
> >> >> - * EXYNOS5250 - CPU frequency scaling 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.
> >> >> -*/
> >> >> -
> >> >> -#include <linux/module.h>
> >> >> -#include <linux/kernel.h>
> >> >> -#include <linux/err.h>
> >> >> -#include <linux/clk.h>
> >> >> -#include <linux/io.h>
> >> >> -#include <linux/slab.h>
> >> >> -#include <linux/cpufreq.h>
> >> >> -
> >> >> -#include <mach/map.h>
> >> >> -
> >> >> -#include "exynos-cpufreq.h"
> >> >> -
> >> >> -static struct clk *cpu_clk;
> >> >> -static struct clk *moutcore;
> >> >> -static struct clk *mout_mpll;
> >> >> -static struct clk *mout_apll;
> >> >> -
> >> >> -static unsigned int exynos5250_volt_table[] = {
> >> >> -     1300000, 1250000, 1225000, 1200000, 1150000,
> >> >> -     1125000, 1100000, 1075000, 1050000, 1025000,
> >> >> -     1012500, 1000000,  975000,  950000,  937500,
> >> >> -     925000
> >> >> -};
> >> >> -
> >> >> -static struct cpufreq_frequency_table exynos5250_freq_table[]
> >> >> = {
> >> >> -     {L0, 1700 * 1000},
> >> >> -     {L1, 1600 * 1000},
> >> >> -     {L2, 1500 * 1000},
> >> >> -     {L3, 1400 * 1000},
> >> >> -     {L4, 1300 * 1000},
> >> >> -     {L5, 1200 * 1000},
> >> >> -     {L6, 1100 * 1000},
> >> >> -     {L7, 1000 * 1000},
> >> >> -     {L8,  900 * 1000},
> >> >> -     {L9,  800 * 1000},
> >> >> -     {L10, 700 * 1000},
> >> >> -     {L11, 600 * 1000},
> >> >> -     {L12, 500 * 1000},
> >> >> -     {L13, 400 * 1000},
> >> >> -     {L14, 300 * 1000},
> >> >> -     {L15, 200 * 1000},
> >> >> -     {0, CPUFREQ_TABLE_END},
> >> >> -};
> >> >> -
> >> >> -static struct apll_freq apll_freq_5250[] = {
> >> >> -     /*
> >> >> -      * values:
> >> >> -      * freq
> >> >> -      * clock divider for ARM, CPUD, ACP, PERIPH, ATB,
> >> >> PCLK_DBG, APLL, ARM2
> >> >> -      * clock divider for COPY, HPM, RESERVED
> >> >> -      * PLL M, P, S
> >> >> -      */
> >> >> -     APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6,
> >> >> 0),
> >> >> -     APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4,
> >> >> 0),
> >> >> -     APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3,
> >> >> 0),
> >> >> -     APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4,
> >> >> 1),
> >> >> -     APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3,
> >> >> 1),
> >> >> -     APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4,
> >> >> 2),
> >> >> -     APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3,
> >> >> 2), -};
> >> >> -
> >> >> -static void set_clkdiv(unsigned int div_index)
> >> >> -{
> >> >> -     unsigned int tmp;
> >> >> -
> >> >> -     /* Change Divider - CPU0 */
> >> >> -
> >> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu0;
> >> >> -
> >> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
> >> >> -
> >> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
> >> >> -             cpu_relax();
> >> >> -
> >> >> -     /* Change Divider - CPU1 */
> >> >> -     tmp = apll_freq_5250[div_index].clk_div_cpu1;
> >> >> -
> >> >> -     __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
> >> >> -
> >> >> -     while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
> >> >> -             cpu_relax();
> >> >> -}
> >> >> -
> >> >> -static void set_apll(unsigned int index)
> >> >> -{
> >> >> -     unsigned int tmp;
> >> >> -     unsigned int freq = apll_freq_5250[index].freq;
> >> >> -
> >> >> -     /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
> >> >> -     clk_set_parent(moutcore, mout_mpll);
> >> >> -
> >> >> -     do {
> >> >> -             cpu_relax();
> >> >> -             tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
> >> >> -             tmp &= 0x7;
> >> >> -     } while (tmp != 0x2);
> >> >> -
> >> >> -     clk_set_rate(mout_apll, freq * 1000);
> >> >> -
> >> >> -     /* MUX_CORE_SEL = APLL */
> >> >> -     clk_set_parent(moutcore, mout_apll);
> >> >> -
> >> >> -     do {
> >> >> -             cpu_relax();
> >> >> -             tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
> >> >> -             tmp &= (0x7 << 16);
> >> >> -     } while (tmp != (0x1 << 16));
> >> >> -}
> >> >> -
> >> >> -static void exynos5250_set_frequency(unsigned int old_index,
> >> >> -                               unsigned int new_index)
> >> >> -{
> >> >> -     if (old_index > new_index) {
> >> >> -             set_clkdiv(new_index);
> >> >> -             set_apll(new_index);
> >> >> -     } else if (old_index < new_index) {
> >> >> -             set_apll(new_index);
> >> >> -             set_clkdiv(new_index);
> >> >> -     }
> >> >> -}
> >> >> -
> >> >> -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
> >> >> -{
> >> >> -     unsigned long rate;
> >> >> -
> >> >> -     cpu_clk = clk_get(NULL, "armclk");
> >> >> -     if (IS_ERR(cpu_clk))
> >> >> -             return PTR_ERR(cpu_clk);
> >> >> -
> >> >> -     moutcore = clk_get(NULL, "mout_cpu");
> >> >> -     if (IS_ERR(moutcore))
> >> >> -             goto err_moutcore;
> >> >> -
> >> >> -     mout_mpll = clk_get(NULL, "mout_mpll");
> >> >> -     if (IS_ERR(mout_mpll))
> >> >> -             goto err_mout_mpll;
> >> >> -
> >> >> -     rate = clk_get_rate(mout_mpll) / 1000;
> >> >> -
> >> >> -     mout_apll = clk_get(NULL, "mout_apll");
> >> >> -     if (IS_ERR(mout_apll))
> >> >> -             goto err_mout_apll;
> >> >> -
> >> >> -     info->mpll_freq_khz = rate;
> >> >> -     /* 800Mhz */
> >> >> -     info->pll_safe_idx = L9;
> >> >> -     info->cpu_clk = cpu_clk;
> >> >> -     info->volt_table = exynos5250_volt_table;
> >> >> -     info->freq_table = exynos5250_freq_table;
> >> >> -     info->set_freq = exynos5250_set_frequency;
> >> >> -
> >> >> -     return 0;
> >> >> -
> >> >> -err_mout_apll:
> >> >> -     clk_put(mout_mpll);
> >> >> -err_mout_mpll:
> >> >> -     clk_put(moutcore);
> >> >> -err_moutcore:
> >> >> -     clk_put(cpu_clk);
> >> >> -
> >> >> -     pr_err("%s: failed initialization\n", __func__);
> >> >> -     return -EINVAL;
> >> >> -}
> >> >
> >> >
> >> >
> >> > --
> >> > Best regards,
> >> >
> >> > Lukasz Majewski
> >> >
> >> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe cpufreq"
> >> in the body of a message to majordomo at vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>
> >
> >
> >
> > --
> > Best regards,
> >
> > Lukasz Majewski
> >
> > Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-02-05 12:43         ` Thomas Abraham
  2014-02-05 13:15           ` Lukasz Majewski
@ 2014-02-05 13:36           ` Nishanth Menon
  2014-02-05 13:49             ` Lukasz Majewski
  1 sibling, 1 reply; 51+ messages in thread
From: Nishanth Menon @ 2014-02-05 13:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 5, 2014 at 6:43 AM, Thomas Abraham <ta.omasab@gmail.com> wrote:
> Okay, thanks. Initially it looked like adding boost frequencies into
> operating-modes would convolute it but I guess I was wrong. So I will
> add support for looking up "boost-frequencies" property in
> dev_pm_opp_init_cpufreq_table function and mark the frequencies listed
> in this binding as CPUFREQ_BOOST_FREQ.
I wonder if it is high time that we pop the cpufreq stuff out of opp.c
other frameworks such as devfreq might choose to do things
differently.
Regards,
Nishanth Menon

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

* [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-02-05 13:36           ` Nishanth Menon
@ 2014-02-05 13:49             ` Lukasz Majewski
  0 siblings, 0 replies; 51+ messages in thread
From: Lukasz Majewski @ 2014-02-05 13:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nishanth,

> On Wed, Feb 5, 2014 at 6:43 AM, Thomas Abraham <ta.omasab@gmail.com>
> wrote:
> > Okay, thanks. Initially it looked like adding boost frequencies into
> > operating-modes would convolute it but I guess I was wrong. So I
> > will add support for looking up "boost-frequencies" property in
> > dev_pm_opp_init_cpufreq_table function and mark the frequencies
> > listed in this binding as CPUFREQ_BOOST_FREQ.
> I wonder if it is high time that we pop the cpufreq stuff out of opp.c
> other frameworks such as devfreq might choose to do things
> differently.

In my opinion, conceptually cpufreq's voltage and freq handling code
fits perfectly to OPP framework.

Yes. We can think about excluding cpufreq related code to e.g.
opp-cpufreq.c (and probably opp-devfreq.c if needed in the future).

> Regards,
> Nishanth Menon
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

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

end of thread, other threads:[~2014-02-05 13:49 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-18 12:10 [PATCH v2 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
2014-01-18 12:10 ` [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
2014-01-20  8:09   ` Lukasz Majewski
2014-01-27  7:16   ` Shawn Guo
2014-01-28  4:30     ` Thomas Abraham
2014-01-27 20:25   ` Mike Turquette
2014-01-28  5:30     ` Thomas Abraham
2014-01-28  8:17       ` Lukasz Majewski
2014-01-28 11:36         ` Thomas Abraham
2014-01-28 15:06           ` Lukasz Majewski
2014-01-28 15:15             ` Thomas Abraham
2014-01-28 11:49       ` Shawn Guo
2014-01-28 12:47         ` Thomas Abraham
2014-01-28 18:47       ` Mike Turquette
2014-01-30 12:53         ` Thomas Abraham
2014-01-30 15:09           ` Heiko Stübner
2014-02-01  4:10             ` Mike Turquette
2014-02-03 16:06               ` Thomas Abraham
2014-02-05  9:53               ` Heiko Stübner
2014-02-03 16:06             ` Thomas Abraham
2014-01-18 12:10 ` [PATCH v2 2/7] clk: samsung: add infrastructure to register cpu clocks Thomas Abraham
2014-01-20  8:24   ` Lukasz Majewski
2014-01-21  8:35     ` Thomas Abraham
2014-01-21 10:25       ` Lukasz Majewski
2014-01-21 10:38         ` Thomas Abraham
2014-01-21 10:59           ` Lukasz Majewski
2014-01-18 12:10 ` [PATCH v2 3/7] devicetree: bindings: add cpu clock configuration data binding for Exynos4/5 Thomas Abraham
2014-01-18 15:22   ` Rob Herring
2014-01-21  7:31     ` Thomas Abraham
2014-01-24 15:24       ` Thomas Abraham
2014-01-18 12:10 ` [PATCH v2 4/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock frequency table Thomas Abraham
2014-01-20  7:32   ` Lukasz Majewski
2014-01-21  7:33     ` Thomas Abraham
2014-01-18 12:10 ` [PATCH v2 5/7] clk: exynos: use cpu-clock provider type to represent arm clock Thomas Abraham
2014-01-20  7:47   ` Lukasz Majewski
2014-01-21  7:52     ` Thomas Abraham
2014-01-21 10:38       ` Lukasz Majewski
2014-01-21 11:15         ` Thomas Abraham
2014-01-21 11:42           ` Lukasz Majewski
2014-01-18 12:10 ` [PATCH v2 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver Thomas Abraham
2014-01-20  7:48   ` Lukasz Majewski
2014-01-18 12:10 ` [PATCH v2 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support Thomas Abraham
2014-01-20  8:08   ` Lukasz Majewski
2014-01-21  8:08     ` Thomas Abraham
2014-01-21  8:27       ` Lukasz Majewski
2014-02-05 10:21     ` Thomas Abraham
2014-02-05 11:44       ` Lukasz Majewski
2014-02-05 12:43         ` Thomas Abraham
2014-02-05 13:15           ` Lukasz Majewski
2014-02-05 13:36           ` Nishanth Menon
2014-02-05 13:49             ` Lukasz Majewski

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