All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms
@ 2014-02-07 15:55 ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

Changes since v2:
- Safe operating voltage is not required while switching APLL frequency
  since the temporary parent's clock is divided down to keep armclk within
  permissible limits. Thanks to Heiko Stübner <heiko@sntech.de> for this
  suggesting this.
- Rob had suggested to use max frequency for each of the divider clock
  outputs instead of divider values. But due to certain SoC specific
  characteristics, the divider values corresponding to the input clock
  frequency for the CMU_CPU clock blocks have to be used.

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).

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

 .../devicetree/bindings/clock/exynos4-clock.txt    |   37 ++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   39 ++
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    2 +
 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                  |   18 +
 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                  |   31 ++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   36 ++
 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                  |   41 ++
 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                      |  409 ++++++++++++++++++++
 drivers/clk/samsung/clk-exynos4.c                  |   23 +-
 drivers/clk/samsung/clk-exynos5250.c               |   10 +-
 drivers/clk/samsung/clk.h                          |    5 +
 drivers/cpufreq/Kconfig                            |    1 +
 drivers/cpufreq/Kconfig.arm                        |   51 ---
 drivers/cpufreq/Makefile                           |    4 -
 drivers/cpufreq/cpufreq-cpu0.c                     |    3 +
 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 +
 36 files changed, 727 insertions(+), 1019 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.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] 43+ messages in thread

* [PATCH v3 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms
@ 2014-02-07 15:55 ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Changes since v2:
- Safe operating voltage is not required while switching APLL frequency
  since the temporary parent's clock is divided down to keep armclk within
  permissible limits. Thanks to Heiko St?bner <heiko@sntech.de> for this
  suggesting this.
- Rob had suggested to use max frequency for each of the divider clock
  outputs instead of divider values. But due to certain SoC specific
  characteristics, the divider values corresponding to the input clock
  frequency for the CMU_CPU clock blocks have to be used.

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).

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

 .../devicetree/bindings/clock/exynos4-clock.txt    |   37 ++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   39 ++
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    2 +
 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                  |   18 +
 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                  |   31 ++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   36 ++
 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                  |   41 ++
 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                      |  409 ++++++++++++++++++++
 drivers/clk/samsung/clk-exynos4.c                  |   23 +-
 drivers/clk/samsung/clk-exynos5250.c               |   10 +-
 drivers/clk/samsung/clk.h                          |    5 +
 drivers/cpufreq/Kconfig                            |    1 +
 drivers/cpufreq/Kconfig.arm                        |   51 ---
 drivers/cpufreq/Makefile                           |    4 -
 drivers/cpufreq/cpufreq-cpu0.c                     |    3 +
 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 +
 36 files changed, 727 insertions(+), 1019 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.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] 43+ messages in thread

* [PATCH v3 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms
@ 2014-02-07 15:55 ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

Changes since v2:
- Safe operating voltage is not required while switching APLL frequency
  since the temporary parent's clock is divided down to keep armclk within
  permissible limits. Thanks to Heiko Stübner <heiko@sntech.de> for this
  suggesting this.
- Rob had suggested to use max frequency for each of the divider clock
  outputs instead of divider values. But due to certain SoC specific
  characteristics, the divider values corresponding to the input clock
  frequency for the CMU_CPU clock blocks have to be used.

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).

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

 .../devicetree/bindings/clock/exynos4-clock.txt    |   37 ++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   39 ++
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    2 +
 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                  |   18 +
 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                  |   31 ++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   36 ++
 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                  |   41 ++
 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                      |  409 ++++++++++++++++++++
 drivers/clk/samsung/clk-exynos4.c                  |   23 +-
 drivers/clk/samsung/clk-exynos5250.c               |   10 +-
 drivers/clk/samsung/clk.h                          |    5 +
 drivers/cpufreq/Kconfig                            |    1 +
 drivers/cpufreq/Kconfig.arm                        |   51 ---
 drivers/cpufreq/Makefile                           |    4 -
 drivers/cpufreq/cpufreq-cpu0.c                     |    3 +
 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 +
 36 files changed, 727 insertions(+), 1019 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.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] 43+ messages in thread

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

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

Lookup for the optional boost-frequency property in cpu0 node and if
available, enable support for boost mode frequencies. The frequencies
usable in boost mode are determined while preparing the cpufreq table
from the list of operating points available.

In addition to this, enable the CPU_FREQ_BOOST_SW config option for
this driver by default. On platforms that do not support boost mode,
the boost mode frequencies will not be specified in cpu0 node and
hence the boost mode support will not be enabled. Since this driver
anyways depends on THERMAL config option, it is safe to enable
CPU_FREQ_BOOST_SW config option as default.

Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
 drivers/cpufreq/Kconfig                                    |    1 +
 drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
 3 files changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
index f055515..60f321a 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -19,6 +19,8 @@ Optional properties:
 - cooling-min-level:
 - cooling-max-level:
      Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
+- boost-frequency:
+     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
 
 Examples:
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 4b029c0..52cc704 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
 	tristate "Generic CPU0 cpufreq driver"
 	depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
 	select PM_OPP
+	select CPU_FREQ_BOOST_SW
 	help
 	  This adds a generic cpufreq driver for CPU0 frequency management.
 	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 0c12ffc..06539eb 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 			transition_latency += ret * 1000;
 	}
 
+	if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
+		cpu0_cpufreq_driver.boost_supported = true;
+
 	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
 	if (ret) {
 		pr_err("failed register driver: %d\n", ret);
-- 
1.7.10.4

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

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

Lookup for the optional boost-frequency property in cpu0 node and if
available, enable support for boost mode frequencies. The frequencies
usable in boost mode are determined while preparing the cpufreq table
from the list of operating points available.

In addition to this, enable the CPU_FREQ_BOOST_SW config option for
this driver by default. On platforms that do not support boost mode,
the boost mode frequencies will not be specified in cpu0 node and
hence the boost mode support will not be enabled. Since this driver
anyways depends on THERMAL config option, it is safe to enable
CPU_FREQ_BOOST_SW config option as default.

Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
 drivers/cpufreq/Kconfig                                    |    1 +
 drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
 3 files changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
index f055515..60f321a 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -19,6 +19,8 @@ Optional properties:
 - cooling-min-level:
 - cooling-max-level:
      Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
+- boost-frequency:
+     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
 
 Examples:
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 4b029c0..52cc704 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
 	tristate "Generic CPU0 cpufreq driver"
 	depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
 	select PM_OPP
+	select CPU_FREQ_BOOST_SW
 	help
 	  This adds a generic cpufreq driver for CPU0 frequency management.
 	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 0c12ffc..06539eb 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 			transition_latency += ret * 1000;
 	}
 
+	if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
+		cpu0_cpufreq_driver.boost_supported = true;
+
 	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
 	if (ret) {
 		pr_err("failed register driver: %d\n", ret);
-- 
1.7.10.4

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

* [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

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
configuration data for this clock is obtained from device tree. This
implementation is reusable for Exynos4x12 and Exynos5250 SoCs as well.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 drivers/clk/samsung/Makefile  |    2 +-
 drivers/clk/samsung/clk-cpu.c |  409 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h     |    5 +
 3 files changed, 415 insertions(+), 1 deletion(-)
 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..673f620
--- /dev/null
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -0,0 +1,409 @@
+/*
+ * 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
+
+#define MAX_DIV			8
+
+#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
+#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf) + 1)
+
+#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1, d0)			\
+		((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12) |	\
+		 (d1 << 8) | (d0 <<  4))
+#define EXYNOS4210_DIV_CPU1(d2, d1, d0)					\
+		((d2 << 8) | (d1 << 4) | (d0 << 0))
+
+#define EXYNOS4210_DIV1_HPM_MASK	((0x7 << 0) | (0x7 << 4))
+#define EXYNOS4210_MUX_HPM_MASK		(1 << 20)
+
+/**
+ * struct exynos4210_armclk_data: config data to setup exynos4210 cpu clocks.
+ * @prate:	frequency of the parent clock.
+ * @div0:	value to be programmed in the div_cpu0 register.
+ * @div1:	value to be programmed in the div_cpu1 register.
+ *
+ * This structure holds the divider configuration data for divider clocks
+ * belonging to the CMU_CPU clock domain. The parent frequency at which these
+ * divider values are vaild is specified in @prate.
+ */
+struct exynos4210_armclk_data {
+	unsigned long	prate;
+	unsigned int	div0;
+	unsigned int	div1;
+};
+
+/**
+ * struct samsung_cpuclk: information about clock supplied to a CPU core.
+ * @hw:		handle between ccf and cpu clock.
+ * @alt_parent:	alternate parent clock to use when switching the speed
+ *		of the primary parent 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.
+ * @clk_nb:	clock notifier registered for changes in clock speed of the
+ *		primary parent clock.
+ * @data:	optional data which the acutal instantiation of this clock
+ *		can use.
+ */
+struct samsung_cpuclk {
+	struct clk_hw		hw;
+	struct clk		*alt_parent;
+	void __iomem		*ctrl_base;
+	unsigned long		offset;
+	struct notifier_block	clk_nb;
+	void			*data;
+};
+
+#define to_samsung_cpuclk_hw(hw) container_of(hw, struct samsung_cpuclk, hw)
+#define to_samsung_cpuclk_nb(nb) container_of(nb, struct samsung_cpuclk, clk_nb)
+
+/**
+ * struct samsung_cpuclk_soc_data: soc specific data for cpu clocks.
+ * @parser:	pointer to a function that can parse SoC specific data.
+ * @ops:	clock operations to be used for this clock.
+ * @offset:	optional offset from base of clock controller register base, to
+ *		be used when accessing clock controller registers related to the
+ *		cpu clock.
+ * @clk_cb:	the clock notifier callback to be called for changes in the
+ *		clock rate of the primary parent clock.
+ *
+ * This structure provides SoC specific data for ARM clocks. Based on
+ * the compatible value of the clock controller node, the value of the
+ * fields in this structure can be populated.
+ */
+struct samsung_cpuclk_soc_data {
+	int (*parser)(struct device_node *, void **);
+	const struct clk_ops *ops;
+	unsigned int offset;
+	int (*clk_cb)(struct notifier_block *nb, unsigned long evt, void *data);
+};
+
+/* common round rate callback useable for all types of cpu clocks */
+static long samsung_cpuclk_round_rate(struct clk_hw *hw,
+			unsigned long drate, unsigned long *prate)
+{
+	struct clk *parent = __clk_get_parent(hw->clk);
+	unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
+	unsigned long t_prate, best_div = 1;
+	unsigned long delta, min_delta = UINT_MAX;
+
+	do {
+		t_prate = __clk_round_rate(parent, drate * best_div);
+		delta = drate - (t_prate / best_div);
+		if (delta < min_delta) {
+			*prate = t_prate;
+			min_delta = delta;
+		}
+		if (!delta)
+			break;
+		best_div++;
+	} while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
+
+	return t_prate / best_div;
+}
+
+static unsigned long _calc_div(unsigned long prate, unsigned long drate)
+{
+	unsigned long div = prate / drate;
+
+	WARN_ON(div >= MAX_DIV);
+	return (!(prate % drate)) ? div-- : div;
+}
+
+/* helper function to register a cpu clock */
+static int __init samsung_cpuclk_register(unsigned int lookup_id,
+		const char *name, const char **parents,
+		unsigned int num_parents, void __iomem *base,
+		const struct samsung_cpuclk_soc_data *soc_data,
+		struct device_node *np, const struct clk_ops *ops)
+{
+	struct samsung_cpuclk *cpuclk;
+	struct clk_init_data init;
+	struct clk *clk;
+	int ret;
+
+	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
+	if (!cpuclk) {
+		pr_err("%s: could not allocate memory for %s clock\n",
+					__func__, name);
+		return -ENOMEM;
+	}
+
+	init.name = name;
+	init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
+	init.parent_names = parents;
+	init.num_parents = 1;
+	init.ops = ops;
+
+	cpuclk->hw.init = &init;
+	cpuclk->ctrl_base = base;
+
+	if (soc_data && soc_data->parser) {
+		ret = soc_data->parser(np, &cpuclk->data);
+		if (ret) {
+			pr_err("%s: error %d in parsing %s clock data",
+					__func__, ret, name);
+			ret = -EINVAL;
+			goto free_cpuclk;
+		}
+		cpuclk->offset = soc_data->offset;
+		init.ops = soc_data->ops;
+	}
+
+	if (soc_data && soc_data->clk_cb) {
+		cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
+		if (clk_notifier_register(__clk_lookup(parents[0]),
+				&cpuclk->clk_nb)) {
+			pr_err("%s: failed to register clock notifier for %s\n",
+					__func__, name);
+			goto free_cpuclk_data;
+		}
+	}
+
+	if (num_parents == 2) {
+		cpuclk->alt_parent = __clk_lookup(parents[1]);
+		if (!cpuclk->alt_parent) {
+			pr_err("%s: could not lookup alternate parent %s\n",
+					__func__, parents[1]);
+			ret = -EINVAL;
+			goto free_cpuclk_data;
+		}
+	}
+
+	clk = clk_register(NULL, &cpuclk->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
+		ret = PTR_ERR(clk);
+		goto free_cpuclk_data;
+	}
+
+	samsung_clk_add_lookup(clk, lookup_id);
+	return 0;
+
+free_cpuclk_data:
+	kfree(cpuclk->data);
+free_cpuclk:
+	kfree(cpuclk);
+	return ret;
+}
+
+static inline void _exynos4210_set_armclk_div(void __iomem *base,
+			unsigned long div)
+{
+	writel((readl(base + DIV_CPU0) & ~0xf) | div, base + DIV_CPU0);
+	while (readl(base + DIV_STAT_CPU0) != 0)
+		;
+}
+
+static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
+	void __iomem *base = armclk->ctrl_base + armclk->offset;
+
+	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
+				EXYNOS4210_ARM_DIV2(base);
+}
+
+/*
+ * This clock notifier is called when the frequency of the parent clock
+ * of armclk is to be changed. This notifier handles the setting up all
+ * the divider clocks, remux to temporary parent and handling the safe
+ * frequency levels when using temporary parent.
+ */
+static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	struct clk_notifier_data *ndata = data;
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
+	struct exynos4210_armclk_data *armclk_data;
+	unsigned long alt_prate, alt_div, div0, div1, mux_reg;
+	void __iomem *base;
+	bool need_safe_freq;
+
+	armclk_data = armclk->data;
+	base = armclk->ctrl_base + armclk->offset;
+	alt_prate = clk_get_rate(armclk->alt_parent);
+
+	if (event == POST_RATE_CHANGE)
+		goto e4210_armclk_post_rate_change;
+
+	/* pre-rate change. find out the divider values to use for clock data */
+	while (armclk_data->prate != ndata->new_rate) {
+		if (armclk_data->prate == 0)
+			return NOTIFY_BAD;
+		armclk_data++;
+	}
+
+	div0 = armclk_data->div0;
+	div1 = armclk_data->div1;
+	if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
+		div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
+		div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
+	}
+
+	/*
+	 * if the new and old parent clock speed is less than the clock speed
+	 * of the alternate parent, then it should be ensured that at no point
+	 * the armclk speed is more than the old_prate until the dividers are
+	 * set.
+	 */
+	need_safe_freq = ndata->old_rate < alt_prate &&
+				ndata->new_rate < alt_prate;
+	if (need_safe_freq) {
+		alt_div = _calc_div(alt_prate, ndata->old_rate);
+		_exynos4210_set_armclk_div(base, alt_div);
+		div0 |= alt_div;
+	}
+
+	mux_reg = readl(base + SRC_CPU);
+	writel(mux_reg | (1 << 16), base + SRC_CPU);
+	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
+		;
+
+	writel(div0, base + DIV_CPU0);
+	while (readl(base + DIV_STAT_CPU0) != 0)
+		;
+	writel(div1, base + DIV_CPU1);
+	while (readl(base + DIV_STAT_CPU1) != 0)
+		;
+	return NOTIFY_OK;
+
+e4210_armclk_post_rate_change:
+	/* post-rate change event, re-mux back to primary parent */
+	mux_reg = readl(base + SRC_CPU);
+	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
+	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
+			;
+
+	return NOTIFY_OK;
+}
+
+static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long prate)
+{
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
+	void __iomem *base = armclk->ctrl_base + armclk->offset;
+	unsigned long div;
+
+	div = drate < prate ? _calc_div(prate, drate) : 0;
+	_exynos4210_set_armclk_div(base, div);
+	return 0;
+}
+
+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,
+};
+
+/*
+ * parse divider configuration data from dt for all the cpu clock domain
+ * clocks in exynos4210 and compatible SoC's.
+ */
+static int __init exynos4210_armclk_parser(struct device_node *np, void **data)
+{
+	struct exynos4210_armclk_data *tdata;
+	unsigned long cfg[10], row, col;
+	const struct property *prop;
+	const __be32 *val;
+	u32 cells;
+	int ret;
+
+	if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
+		return -EINVAL;
+	prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -EINVAL;
+	if ((prop->length / sizeof(u32)) % cells)
+		return -EINVAL;
+	row = ((prop->length / sizeof(u32)) / cells) + 1;
+
+	*data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
+	if (!*data)
+		ret = -ENOMEM;
+	tdata = *data;
+
+	val = prop->value;
+	for (; row > 1; row--, tdata++) {
+		for (col = 0; col < cells; col++)
+			cfg[col] = be32_to_cpup(val++);
+
+		tdata->prate = cfg[0] * 1000;
+		tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5], cfg[4],
+						cfg[3], cfg[2], cfg[1]);
+		tdata->div1 = cells == 10 ?
+				EXYNOS4210_DIV_CPU1(cfg[9], cfg[8], cfg[7]) :
+				EXYNOS4210_DIV_CPU1(0, cfg[8], cfg[7]);
+	}
+	tdata->prate = 0;
+	return 0;
+}
+
+static const struct samsung_cpuclk_soc_data exynos4210_cpuclk_soc_data = {
+	.parser = exynos4210_armclk_parser,
+	.ops = &exynos4210_armclk_clk_ops,
+	.offset = 0x14200,
+	.clk_cb = exynos4210_armclk_notifier_cb,
+};
+
+static const struct samsung_cpuclk_soc_data exynos5250_cpuclk_soc_data = {
+	.parser = exynos4210_armclk_parser,
+	.ops = &exynos4210_armclk_clk_ops,
+	.offset = 0x200,
+	.clk_cb = exynos4210_armclk_notifier_cb,
+};
+
+static const struct of_device_id samsung_clock_ids_armclk[] = {
+	{ .compatible = "samsung,exynos4210-clock",
+			.data = &exynos4210_cpuclk_soc_data, },
+	{ .compatible = "samsung,exynos4412-clock",
+			.data = &exynos4210_cpuclk_soc_data, },
+	{ .compatible = "samsung,exynos5250-clock",
+			.data = &exynos5250_cpuclk_soc_data, },
+	{ },
+};
+
+/**
+ * samsung_register_arm_clock: register arm clock with ccf.
+ * @lookup_id: armclk clock output id for the clock controller.
+ * @parent: name of the parent clock for armclk.
+ * @base: base address of the clock controller from which armclk is generated.
+ * @np: device tree node pointer of the clock controller (optional).
+ * @ops: clock ops for this clock (optional)
+ */
+int __init samsung_register_arm_clock(unsigned int lookup_id,
+		const char **parent_names, unsigned int num_parents,
+		void __iomem *base, struct device_node *np, struct clk_ops *ops)
+{
+	const struct of_device_id *match;
+	const struct samsung_cpuclk_soc_data *data = NULL;
+
+	if (np) {
+		match = of_match_node(samsung_clock_ids_armclk, np);
+		data = match ? match->data : NULL;
+	}
+
+	return samsung_cpuclk_register(lookup_id, "armclk", parent_names,
+			num_parents, base, data, np, ops);
+}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 31b4174..5459856 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -340,4 +340,9 @@ extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
 
 extern unsigned long _get_rate(const char *clk_name);
 
+int __init samsung_register_arm_clock(unsigned int lookup_id,
+		const char **parent_names, unsigned int num_parents,
+		void __iomem *base, struct device_node *np,
+		struct clk_ops *ops);
+
 #endif /* __SAMSUNG_CLK_H */
-- 
1.7.10.4


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

* [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 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
configuration data for this clock is obtained from device tree. This
implementation is reusable for Exynos4x12 and Exynos5250 SoCs as well.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 drivers/clk/samsung/Makefile  |    2 +-
 drivers/clk/samsung/clk-cpu.c |  409 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h     |    5 +
 3 files changed, 415 insertions(+), 1 deletion(-)
 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..673f620
--- /dev/null
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -0,0 +1,409 @@
+/*
+ * 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
+
+#define MAX_DIV			8
+
+#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
+#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf) + 1)
+
+#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1, d0)			\
+		((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12) |	\
+		 (d1 << 8) | (d0 <<  4))
+#define EXYNOS4210_DIV_CPU1(d2, d1, d0)					\
+		((d2 << 8) | (d1 << 4) | (d0 << 0))
+
+#define EXYNOS4210_DIV1_HPM_MASK	((0x7 << 0) | (0x7 << 4))
+#define EXYNOS4210_MUX_HPM_MASK		(1 << 20)
+
+/**
+ * struct exynos4210_armclk_data: config data to setup exynos4210 cpu clocks.
+ * @prate:	frequency of the parent clock.
+ * @div0:	value to be programmed in the div_cpu0 register.
+ * @div1:	value to be programmed in the div_cpu1 register.
+ *
+ * This structure holds the divider configuration data for divider clocks
+ * belonging to the CMU_CPU clock domain. The parent frequency@which these
+ * divider values are vaild is specified in @prate.
+ */
+struct exynos4210_armclk_data {
+	unsigned long	prate;
+	unsigned int	div0;
+	unsigned int	div1;
+};
+
+/**
+ * struct samsung_cpuclk: information about clock supplied to a CPU core.
+ * @hw:		handle between ccf and cpu clock.
+ * @alt_parent:	alternate parent clock to use when switching the speed
+ *		of the primary parent 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.
+ * @clk_nb:	clock notifier registered for changes in clock speed of the
+ *		primary parent clock.
+ * @data:	optional data which the acutal instantiation of this clock
+ *		can use.
+ */
+struct samsung_cpuclk {
+	struct clk_hw		hw;
+	struct clk		*alt_parent;
+	void __iomem		*ctrl_base;
+	unsigned long		offset;
+	struct notifier_block	clk_nb;
+	void			*data;
+};
+
+#define to_samsung_cpuclk_hw(hw) container_of(hw, struct samsung_cpuclk, hw)
+#define to_samsung_cpuclk_nb(nb) container_of(nb, struct samsung_cpuclk, clk_nb)
+
+/**
+ * struct samsung_cpuclk_soc_data: soc specific data for cpu clocks.
+ * @parser:	pointer to a function that can parse SoC specific data.
+ * @ops:	clock operations to be used for this clock.
+ * @offset:	optional offset from base of clock controller register base, to
+ *		be used when accessing clock controller registers related to the
+ *		cpu clock.
+ * @clk_cb:	the clock notifier callback to be called for changes in the
+ *		clock rate of the primary parent clock.
+ *
+ * This structure provides SoC specific data for ARM clocks. Based on
+ * the compatible value of the clock controller node, the value of the
+ * fields in this structure can be populated.
+ */
+struct samsung_cpuclk_soc_data {
+	int (*parser)(struct device_node *, void **);
+	const struct clk_ops *ops;
+	unsigned int offset;
+	int (*clk_cb)(struct notifier_block *nb, unsigned long evt, void *data);
+};
+
+/* common round rate callback useable for all types of cpu clocks */
+static long samsung_cpuclk_round_rate(struct clk_hw *hw,
+			unsigned long drate, unsigned long *prate)
+{
+	struct clk *parent = __clk_get_parent(hw->clk);
+	unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
+	unsigned long t_prate, best_div = 1;
+	unsigned long delta, min_delta = UINT_MAX;
+
+	do {
+		t_prate = __clk_round_rate(parent, drate * best_div);
+		delta = drate - (t_prate / best_div);
+		if (delta < min_delta) {
+			*prate = t_prate;
+			min_delta = delta;
+		}
+		if (!delta)
+			break;
+		best_div++;
+	} while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
+
+	return t_prate / best_div;
+}
+
+static unsigned long _calc_div(unsigned long prate, unsigned long drate)
+{
+	unsigned long div = prate / drate;
+
+	WARN_ON(div >= MAX_DIV);
+	return (!(prate % drate)) ? div-- : div;
+}
+
+/* helper function to register a cpu clock */
+static int __init samsung_cpuclk_register(unsigned int lookup_id,
+		const char *name, const char **parents,
+		unsigned int num_parents, void __iomem *base,
+		const struct samsung_cpuclk_soc_data *soc_data,
+		struct device_node *np, const struct clk_ops *ops)
+{
+	struct samsung_cpuclk *cpuclk;
+	struct clk_init_data init;
+	struct clk *clk;
+	int ret;
+
+	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
+	if (!cpuclk) {
+		pr_err("%s: could not allocate memory for %s clock\n",
+					__func__, name);
+		return -ENOMEM;
+	}
+
+	init.name = name;
+	init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
+	init.parent_names = parents;
+	init.num_parents = 1;
+	init.ops = ops;
+
+	cpuclk->hw.init = &init;
+	cpuclk->ctrl_base = base;
+
+	if (soc_data && soc_data->parser) {
+		ret = soc_data->parser(np, &cpuclk->data);
+		if (ret) {
+			pr_err("%s: error %d in parsing %s clock data",
+					__func__, ret, name);
+			ret = -EINVAL;
+			goto free_cpuclk;
+		}
+		cpuclk->offset = soc_data->offset;
+		init.ops = soc_data->ops;
+	}
+
+	if (soc_data && soc_data->clk_cb) {
+		cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
+		if (clk_notifier_register(__clk_lookup(parents[0]),
+				&cpuclk->clk_nb)) {
+			pr_err("%s: failed to register clock notifier for %s\n",
+					__func__, name);
+			goto free_cpuclk_data;
+		}
+	}
+
+	if (num_parents == 2) {
+		cpuclk->alt_parent = __clk_lookup(parents[1]);
+		if (!cpuclk->alt_parent) {
+			pr_err("%s: could not lookup alternate parent %s\n",
+					__func__, parents[1]);
+			ret = -EINVAL;
+			goto free_cpuclk_data;
+		}
+	}
+
+	clk = clk_register(NULL, &cpuclk->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
+		ret = PTR_ERR(clk);
+		goto free_cpuclk_data;
+	}
+
+	samsung_clk_add_lookup(clk, lookup_id);
+	return 0;
+
+free_cpuclk_data:
+	kfree(cpuclk->data);
+free_cpuclk:
+	kfree(cpuclk);
+	return ret;
+}
+
+static inline void _exynos4210_set_armclk_div(void __iomem *base,
+			unsigned long div)
+{
+	writel((readl(base + DIV_CPU0) & ~0xf) | div, base + DIV_CPU0);
+	while (readl(base + DIV_STAT_CPU0) != 0)
+		;
+}
+
+static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
+	void __iomem *base = armclk->ctrl_base + armclk->offset;
+
+	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
+				EXYNOS4210_ARM_DIV2(base);
+}
+
+/*
+ * This clock notifier is called when the frequency of the parent clock
+ * of armclk is to be changed. This notifier handles the setting up all
+ * the divider clocks, remux to temporary parent and handling the safe
+ * frequency levels when using temporary parent.
+ */
+static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
+				unsigned long event, void *data)
+{
+	struct clk_notifier_data *ndata = data;
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
+	struct exynos4210_armclk_data *armclk_data;
+	unsigned long alt_prate, alt_div, div0, div1, mux_reg;
+	void __iomem *base;
+	bool need_safe_freq;
+
+	armclk_data = armclk->data;
+	base = armclk->ctrl_base + armclk->offset;
+	alt_prate = clk_get_rate(armclk->alt_parent);
+
+	if (event == POST_RATE_CHANGE)
+		goto e4210_armclk_post_rate_change;
+
+	/* pre-rate change. find out the divider values to use for clock data */
+	while (armclk_data->prate != ndata->new_rate) {
+		if (armclk_data->prate == 0)
+			return NOTIFY_BAD;
+		armclk_data++;
+	}
+
+	div0 = armclk_data->div0;
+	div1 = armclk_data->div1;
+	if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
+		div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
+		div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
+	}
+
+	/*
+	 * if the new and old parent clock speed is less than the clock speed
+	 * of the alternate parent, then it should be ensured that at no point
+	 * the armclk speed is more than the old_prate until the dividers are
+	 * set.
+	 */
+	need_safe_freq = ndata->old_rate < alt_prate &&
+				ndata->new_rate < alt_prate;
+	if (need_safe_freq) {
+		alt_div = _calc_div(alt_prate, ndata->old_rate);
+		_exynos4210_set_armclk_div(base, alt_div);
+		div0 |= alt_div;
+	}
+
+	mux_reg = readl(base + SRC_CPU);
+	writel(mux_reg | (1 << 16), base + SRC_CPU);
+	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
+		;
+
+	writel(div0, base + DIV_CPU0);
+	while (readl(base + DIV_STAT_CPU0) != 0)
+		;
+	writel(div1, base + DIV_CPU1);
+	while (readl(base + DIV_STAT_CPU1) != 0)
+		;
+	return NOTIFY_OK;
+
+e4210_armclk_post_rate_change:
+	/* post-rate change event, re-mux back to primary parent */
+	mux_reg = readl(base + SRC_CPU);
+	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
+	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
+			;
+
+	return NOTIFY_OK;
+}
+
+static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long drate,
+					unsigned long prate)
+{
+	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
+	void __iomem *base = armclk->ctrl_base + armclk->offset;
+	unsigned long div;
+
+	div = drate < prate ? _calc_div(prate, drate) : 0;
+	_exynos4210_set_armclk_div(base, div);
+	return 0;
+}
+
+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,
+};
+
+/*
+ * parse divider configuration data from dt for all the cpu clock domain
+ * clocks in exynos4210 and compatible SoC's.
+ */
+static int __init exynos4210_armclk_parser(struct device_node *np, void **data)
+{
+	struct exynos4210_armclk_data *tdata;
+	unsigned long cfg[10], row, col;
+	const struct property *prop;
+	const __be32 *val;
+	u32 cells;
+	int ret;
+
+	if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
+		return -EINVAL;
+	prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -EINVAL;
+	if ((prop->length / sizeof(u32)) % cells)
+		return -EINVAL;
+	row = ((prop->length / sizeof(u32)) / cells) + 1;
+
+	*data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
+	if (!*data)
+		ret = -ENOMEM;
+	tdata = *data;
+
+	val = prop->value;
+	for (; row > 1; row--, tdata++) {
+		for (col = 0; col < cells; col++)
+			cfg[col] = be32_to_cpup(val++);
+
+		tdata->prate = cfg[0] * 1000;
+		tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5], cfg[4],
+						cfg[3], cfg[2], cfg[1]);
+		tdata->div1 = cells == 10 ?
+				EXYNOS4210_DIV_CPU1(cfg[9], cfg[8], cfg[7]) :
+				EXYNOS4210_DIV_CPU1(0, cfg[8], cfg[7]);
+	}
+	tdata->prate = 0;
+	return 0;
+}
+
+static const struct samsung_cpuclk_soc_data exynos4210_cpuclk_soc_data = {
+	.parser = exynos4210_armclk_parser,
+	.ops = &exynos4210_armclk_clk_ops,
+	.offset = 0x14200,
+	.clk_cb = exynos4210_armclk_notifier_cb,
+};
+
+static const struct samsung_cpuclk_soc_data exynos5250_cpuclk_soc_data = {
+	.parser = exynos4210_armclk_parser,
+	.ops = &exynos4210_armclk_clk_ops,
+	.offset = 0x200,
+	.clk_cb = exynos4210_armclk_notifier_cb,
+};
+
+static const struct of_device_id samsung_clock_ids_armclk[] = {
+	{ .compatible = "samsung,exynos4210-clock",
+			.data = &exynos4210_cpuclk_soc_data, },
+	{ .compatible = "samsung,exynos4412-clock",
+			.data = &exynos4210_cpuclk_soc_data, },
+	{ .compatible = "samsung,exynos5250-clock",
+			.data = &exynos5250_cpuclk_soc_data, },
+	{ },
+};
+
+/**
+ * samsung_register_arm_clock: register arm clock with ccf.
+ * @lookup_id: armclk clock output id for the clock controller.
+ * @parent: name of the parent clock for armclk.
+ * @base: base address of the clock controller from which armclk is generated.
+ * @np: device tree node pointer of the clock controller (optional).
+ * @ops: clock ops for this clock (optional)
+ */
+int __init samsung_register_arm_clock(unsigned int lookup_id,
+		const char **parent_names, unsigned int num_parents,
+		void __iomem *base, struct device_node *np, struct clk_ops *ops)
+{
+	const struct of_device_id *match;
+	const struct samsung_cpuclk_soc_data *data = NULL;
+
+	if (np) {
+		match = of_match_node(samsung_clock_ids_armclk, np);
+		data = match ? match->data : NULL;
+	}
+
+	return samsung_cpuclk_register(lookup_id, "armclk", parent_names,
+			num_parents, base, data, np, ops);
+}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 31b4174..5459856 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -340,4 +340,9 @@ extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
 
 extern unsigned long _get_rate(const char *clk_name);
 
+int __init samsung_register_arm_clock(unsigned int lookup_id,
+		const char **parent_names, unsigned int num_parents,
+		void __iomem *base, struct device_node *np,
+		struct clk_ops *ops);
+
 #endif /* __SAMSUNG_CLK_H */
-- 
1.7.10.4

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

* [PATCH v3 3/7] Documentation: devicetree: add cpu clock configuration data binding for Exynos4/5
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree

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

The clock blocks within the CMU_CPU clock domain are put together into a
new composite clock type called the cpu clock. This clock type requires
configuration data that will be atomically programmed in the multiple
clock blocks encapsulated within the cpu clock type when the parent clock
frequency is changed. 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: Tomasz Figa <t.figa@samsung.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: <devicetree@vger.kernel.org>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/clock/exynos4-clock.txt    |   37 +++++++++++++++++++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   38 ++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
index a2ac2d9..b505e17 100644
--- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
@@ -15,6 +15,35 @@ Required Properties:
 
 - #clock-cells: should be 1.
 
+- samsung,armclk-divider-table: when the frequency of the APLL is changed
+  the divider clocks in CMU_CPU clock domain also need to be updated. These
+  divider clocks have SoC specific divider clock output requirements for a
+  specific APLL clock speeds. When APLL clock rate is changed, these divider
+  clocks are reprogrammed with pre-determined values in order to maintain the
+  SoC specific divider clock outputs. This property lists the divider values
+  for divider clocks in the CMU_CPU block for supported APLL clock speeds.
+  The format of each entry included in the arm-frequency-table should be
+  as defined below
+
+  - for Exynos4210 and Exynos4212 based platforms:
+      cell #1: arm clock parent frequency
+      cell #2 ~ cell 9#: value of clock divider in the following order
+	        corem0_ratio, corem1_ratio, periph_ratio, atb_ratio,
+		pclk_dbg_ratio, apll_ratio, copy_ratio, hpm_ratio.
+
+  - for Exynos4412 based platforms:
+      cell #1: expected arm clock parent frequency
+      cell #2 ~ cell #10: value of clock divider in the following order
+	       corem0_ratio, corem1_ratio, periph_ratio, atb_ratio,
+               pclk_dbg_ratio, apll_ratio, copy_ratio, hpm_ratio, cores_ratio
+
+- samsung,armclk-cells: defines the number of cells in
+  samsung,armclk-divider-table property. The value of this property depends on
+  the SoC type.
+
+  - for Exynos4210 and Exynos4212: the value should be 9.
+  - for Exynos4412: the value should be 10.
+
 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 +304,14 @@ Example 1: An example of a clock controller node is listed below.
 		compatible = "samsung,exynos4210-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1200000 3 7 3 4 1 7 5 0>,
+					       <1000000 3 7 3 4 1 7 4 0>,
+					       < 800000 3 7 3 3 1 7 3 0>,
+					       < 500000 3 7 3 3 1 7 3 0>,
+					       < 400000 3 7 3 3 1 7 3 0>,
+					       < 200000 1 3 1 1 1 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..9ca818e 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -13,6 +13,25 @@ Required Properties:
 
 - #clock-cells: should be 1.
 
+- samsung,armclk-divider-table: when the frequency of the APLL is changed
+  the divider clocks in CMU_CPU clock domain also need to be updated. These
+  divider clocks have SoC specific divider clock output requirements for a
+  specific APLL clock speeds. When APLL clock rate is changed, these divider
+  clocks are reprogrammed with pre-determined values in order to maintain the
+  SoC specific divider clock outputs. This property lists the divider values
+  for divider clocks in the CMU_CPU block for supported APLL clock speeds.
+  The format of each entry included in the arm-frequency-table should be
+  as defined below
+
+      cell #1: expected arm clock parent frequency
+      cell #2 ~ cell #9: value of clock divider in the following order
+	       cpud_ratio, acp_ratio, periph_ratio, atb_ratio,
+               pclk_dbg_ratio, apll_ratio, copy_ratio, hpm_ratio
+
+- samsung,armclk-cells: defines the number of cells in
+  samsung,armclk-divider-table property. The value of this property should be 9.
+
+
 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 +196,25 @@ Example 1: An example of a clock controller node is listed below.
 		compatible = "samsung,exynos5250-clock";
 		reg = <0x10010000 0x30000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1700000 3 7 7 7 3 5 0 2>,
+					       <1600000 3 7 7 7 1 4 0 2>,
+					       <1500000 2 7 7 7 1 4 0 2>,
+					       <1400000 2 7 7 6 1 4 0 2>,
+					       <1300000 2 7 7 6 1 3 0 2>,
+					       <1200000 2 7 7 5 1 3 0 2>,
+					       <1100000 3 7 7 5 1 3 0 2>,
+					       <1000000 1 7 7 4 1 2 0 2>,
+					       < 900000 1 7 7 4 1 2 0 2>,
+					       < 800000 1 7 7 4 1 2 0 2>,
+					       < 700000 1 7 7 3 1 1 0 2>,
+					       < 600000 1 7 7 3 1 1 0 2>,
+					       < 500000 1 7 7 2 1 1 0 2>,
+					       < 400000 1 7 7 2 1 1 0 2>,
+					       < 300000 1 7 7 1 1 1 0 2>,
+					       < 200000 1 7 7 1 1 1 0 2>;
+
 	};
 
 Example 2: UART controller node that consumes the clock generated by the clock
-- 
1.7.10.4

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

* [PATCH v3 3/7] Documentation: devicetree: add cpu clock configuration data binding for Exynos4/5
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

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

The clock blocks within the CMU_CPU clock domain are put together into a
new composite clock type called the cpu clock. This clock type requires
configuration data that will be atomically programmed in the multiple
clock blocks encapsulated within the cpu clock type when the parent clock
frequency is changed. 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: Tomasz Figa <t.figa@samsung.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: <devicetree@vger.kernel.org>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/clock/exynos4-clock.txt    |   37 +++++++++++++++++++
 .../devicetree/bindings/clock/exynos5250-clock.txt |   38 ++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/exynos4-clock.txt b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
index a2ac2d9..b505e17 100644
--- a/Documentation/devicetree/bindings/clock/exynos4-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos4-clock.txt
@@ -15,6 +15,35 @@ Required Properties:
 
 - #clock-cells: should be 1.
 
+- samsung,armclk-divider-table: when the frequency of the APLL is changed
+  the divider clocks in CMU_CPU clock domain also need to be updated. These
+  divider clocks have SoC specific divider clock output requirements for a
+  specific APLL clock speeds. When APLL clock rate is changed, these divider
+  clocks are reprogrammed with pre-determined values in order to maintain the
+  SoC specific divider clock outputs. This property lists the divider values
+  for divider clocks in the CMU_CPU block for supported APLL clock speeds.
+  The format of each entry included in the arm-frequency-table should be
+  as defined below
+
+  - for Exynos4210 and Exynos4212 based platforms:
+      cell #1: arm clock parent frequency
+      cell #2 ~ cell 9#: value of clock divider in the following order
+	        corem0_ratio, corem1_ratio, periph_ratio, atb_ratio,
+		pclk_dbg_ratio, apll_ratio, copy_ratio, hpm_ratio.
+
+  - for Exynos4412 based platforms:
+      cell #1: expected arm clock parent frequency
+      cell #2 ~ cell #10: value of clock divider in the following order
+	       corem0_ratio, corem1_ratio, periph_ratio, atb_ratio,
+               pclk_dbg_ratio, apll_ratio, copy_ratio, hpm_ratio, cores_ratio
+
+- samsung,armclk-cells: defines the number of cells in
+  samsung,armclk-divider-table property. The value of this property depends on
+  the SoC type.
+
+  - for Exynos4210 and Exynos4212: the value should be 9.
+  - for Exynos4412: the value should be 10.
+
 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 +304,14 @@ Example 1: An example of a clock controller node is listed below.
 		compatible = "samsung,exynos4210-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1200000 3 7 3 4 1 7 5 0>,
+					       <1000000 3 7 3 4 1 7 4 0>,
+					       < 800000 3 7 3 3 1 7 3 0>,
+					       < 500000 3 7 3 3 1 7 3 0>,
+					       < 400000 3 7 3 3 1 7 3 0>,
+					       < 200000 1 3 1 1 1 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..9ca818e 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -13,6 +13,25 @@ Required Properties:
 
 - #clock-cells: should be 1.
 
+- samsung,armclk-divider-table: when the frequency of the APLL is changed
+  the divider clocks in CMU_CPU clock domain also need to be updated. These
+  divider clocks have SoC specific divider clock output requirements for a
+  specific APLL clock speeds. When APLL clock rate is changed, these divider
+  clocks are reprogrammed with pre-determined values in order to maintain the
+  SoC specific divider clock outputs. This property lists the divider values
+  for divider clocks in the CMU_CPU block for supported APLL clock speeds.
+  The format of each entry included in the arm-frequency-table should be
+  as defined below
+
+      cell #1: expected arm clock parent frequency
+      cell #2 ~ cell #9: value of clock divider in the following order
+	       cpud_ratio, acp_ratio, periph_ratio, atb_ratio,
+               pclk_dbg_ratio, apll_ratio, copy_ratio, hpm_ratio
+
+- samsung,armclk-cells: defines the number of cells in
+  samsung,armclk-divider-table property. The value of this property should be 9.
+
+
 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 +196,25 @@ Example 1: An example of a clock controller node is listed below.
 		compatible = "samsung,exynos5250-clock";
 		reg = <0x10010000 0x30000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1700000 3 7 7 7 3 5 0 2>,
+					       <1600000 3 7 7 7 1 4 0 2>,
+					       <1500000 2 7 7 7 1 4 0 2>,
+					       <1400000 2 7 7 6 1 4 0 2>,
+					       <1300000 2 7 7 6 1 3 0 2>,
+					       <1200000 2 7 7 5 1 3 0 2>,
+					       <1100000 3 7 7 5 1 3 0 2>,
+					       <1000000 1 7 7 4 1 2 0 2>,
+					       < 900000 1 7 7 4 1 2 0 2>,
+					       < 800000 1 7 7 4 1 2 0 2>,
+					       < 700000 1 7 7 3 1 1 0 2>,
+					       < 600000 1 7 7 3 1 1 0 2>,
+					       < 500000 1 7 7 2 1 1 0 2>,
+					       < 400000 1 7 7 2 1 1 0 2>,
+					       < 300000 1 7 7 1 1 1 0 2>,
+					       < 200000 1 7 7 1 1 1 0 2>;
+
 	};
 
 Example 2: UART controller node that consumes the clock generated by the clock
-- 
1.7.10.4

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

* [PATCH v3 4/7] clk: exynos: use cpu-clock provider type to represent arm clock
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

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>
---
 drivers/clk/samsung/clk-exynos4.c      |   23 +++++++----------------
 drivers/clk/samsung/clk-exynos5250.c   |   10 +++++-----
 include/dt-bindings/clock/exynos5250.h |    1 +
 3 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 010f071..a52c622 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -336,7 +336,6 @@ static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
 	MUX(0, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
 	MUX(0, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
 	MUX(CLK_SCLK_MPLL, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1),
-	MUX(CLK_MOUT_CORE, "mout_core", mout_core_p4210, SRC_CPU, 16, 1),
 	MUX(CLK_SCLK_VPLL, "sclk_vpll", sclk_vpll_p4210, SRC_TOP0, 8, 1),
 	MUX(CLK_MOUT_FIMC0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
 	MUX(CLK_MOUT_FIMC1, "mout_fimc1", group1_p4210, SRC_CAM, 4, 4),
@@ -395,7 +394,6 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
 	MUX(0, "mout_jpeg", mout_jpeg_p, E4X12_SRC_CAM1, 8, 1),
 	MUX(CLK_SCLK_MPLL, "sclk_mpll", mout_mpll_p, SRC_DMC, 12, 1),
 	MUX(CLK_SCLK_VPLL, "sclk_vpll", mout_vpll_p, SRC_TOP0, 8, 1),
-	MUX(CLK_MOUT_CORE, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
 	MUX(CLK_MOUT_FIMC0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
 	MUX(CLK_MOUT_FIMC1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
 	MUX(CLK_MOUT_FIMC2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
@@ -437,8 +435,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 +480,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,
@@ -868,12 +864,6 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
 		0),
 };
 
-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"),
-};
-
 static struct samsung_clock_alias exynos4210_aliases[] __initdata = {
 	ALIAS(CLK_SCLK_MPLL, NULL, "mout_mpll"),
 };
@@ -1111,6 +1101,8 @@ static void __init exynos4_clk_init(struct device_node *np,
 			ARRAY_SIZE(exynos4210_gate_clks));
 		samsung_clk_register_alias(exynos4210_aliases,
 			ARRAY_SIZE(exynos4210_aliases));
+		samsung_register_arm_clock(CLK_ARM_CLK, mout_core_p4210,
+			ARRAY_SIZE(mout_core_p4210), reg_base, np, NULL);
 	} else {
 		samsung_clk_register_mux(exynos4x12_mux_clks,
 			ARRAY_SIZE(exynos4x12_mux_clks));
@@ -1120,17 +1112,16 @@ static void __init exynos4_clk_init(struct device_node *np,
 			ARRAY_SIZE(exynos4x12_gate_clks));
 		samsung_clk_register_alias(exynos4x12_aliases,
 			ARRAY_SIZE(exynos4x12_aliases));
+		samsung_register_arm_clock(CLK_ARM_CLK, mout_core_p4x12,
+			ARRAY_SIZE(mout_core_p4x12), reg_base, np, NULL);
 	}
 
-	samsung_clk_register_alias(exynos4_aliases,
-			ARRAY_SIZE(exynos4_aliases));
-
 	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..59742bb 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -219,7 +219,6 @@ static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
 	 */
 	MUX_FA(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
 					CLK_SET_RATE_PARENT, 0, "mout_apll"),
-	MUX_A(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1, "mout_cpu"),
 
 	/*
 	 * CMU_CORE
@@ -298,9 +297,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 +682,10 @@ 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(CLK_ARM_CLK, mout_cpu_p,
+			ARRAY_SIZE(mout_cpu_p), reg_base, np, NULL);
 
 	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.7.10.4

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

* [PATCH v3 4/7] clk: exynos: use cpu-clock provider type to represent arm clock
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 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>
---
 drivers/clk/samsung/clk-exynos4.c      |   23 +++++++----------------
 drivers/clk/samsung/clk-exynos5250.c   |   10 +++++-----
 include/dt-bindings/clock/exynos5250.h |    1 +
 3 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 010f071..a52c622 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -336,7 +336,6 @@ static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
 	MUX(0, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
 	MUX(0, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
 	MUX(CLK_SCLK_MPLL, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1),
-	MUX(CLK_MOUT_CORE, "mout_core", mout_core_p4210, SRC_CPU, 16, 1),
 	MUX(CLK_SCLK_VPLL, "sclk_vpll", sclk_vpll_p4210, SRC_TOP0, 8, 1),
 	MUX(CLK_MOUT_FIMC0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
 	MUX(CLK_MOUT_FIMC1, "mout_fimc1", group1_p4210, SRC_CAM, 4, 4),
@@ -395,7 +394,6 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
 	MUX(0, "mout_jpeg", mout_jpeg_p, E4X12_SRC_CAM1, 8, 1),
 	MUX(CLK_SCLK_MPLL, "sclk_mpll", mout_mpll_p, SRC_DMC, 12, 1),
 	MUX(CLK_SCLK_VPLL, "sclk_vpll", mout_vpll_p, SRC_TOP0, 8, 1),
-	MUX(CLK_MOUT_CORE, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
 	MUX(CLK_MOUT_FIMC0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
 	MUX(CLK_MOUT_FIMC1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
 	MUX(CLK_MOUT_FIMC2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
@@ -437,8 +435,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 +480,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,
@@ -868,12 +864,6 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
 		0),
 };
 
-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"),
-};
-
 static struct samsung_clock_alias exynos4210_aliases[] __initdata = {
 	ALIAS(CLK_SCLK_MPLL, NULL, "mout_mpll"),
 };
@@ -1111,6 +1101,8 @@ static void __init exynos4_clk_init(struct device_node *np,
 			ARRAY_SIZE(exynos4210_gate_clks));
 		samsung_clk_register_alias(exynos4210_aliases,
 			ARRAY_SIZE(exynos4210_aliases));
+		samsung_register_arm_clock(CLK_ARM_CLK, mout_core_p4210,
+			ARRAY_SIZE(mout_core_p4210), reg_base, np, NULL);
 	} else {
 		samsung_clk_register_mux(exynos4x12_mux_clks,
 			ARRAY_SIZE(exynos4x12_mux_clks));
@@ -1120,17 +1112,16 @@ static void __init exynos4_clk_init(struct device_node *np,
 			ARRAY_SIZE(exynos4x12_gate_clks));
 		samsung_clk_register_alias(exynos4x12_aliases,
 			ARRAY_SIZE(exynos4x12_aliases));
+		samsung_register_arm_clock(CLK_ARM_CLK, mout_core_p4x12,
+			ARRAY_SIZE(mout_core_p4x12), reg_base, np, NULL);
 	}
 
-	samsung_clk_register_alias(exynos4_aliases,
-			ARRAY_SIZE(exynos4_aliases));
-
 	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..59742bb 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -219,7 +219,6 @@ static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
 	 */
 	MUX_FA(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
 					CLK_SET_RATE_PARENT, 0, "mout_apll"),
-	MUX_A(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1, "mout_cpu"),
 
 	/*
 	 * CMU_CORE
@@ -298,9 +297,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 +682,10 @@ 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(CLK_ARM_CLK, mout_cpu_p,
+			ARRAY_SIZE(mout_cpu_p), reg_base, np, NULL);
 
 	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.7.10.4

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

* [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

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

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

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
 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                  |   18 +++++++++
 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                  |   31 +++++++++++++++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   36 +++++++++++++++++
 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                  |   41 ++++++++++++++++++++
 15 files changed, 216 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 9ca818e..4513cbb 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -43,6 +43,7 @@ clock which they consume.
   ----------------------------
 
   fin_pll		1
+  armclk		12
 
   [Clock Gate for Special Clocks]
 
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@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..25487d76 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@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@0 {
+			cpu0-supply = <&vdd_arm_reg>;
+		};
+	};
+
 	mct@10050000 {
 		compatible = "none";
 	};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 48ecd7a..a774247 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -36,6 +36,33 @@
 		reg = <0x10023CA0 0x20>;
 	};
 
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			clocks = <&clock 12>;
+			clock-names = "cpu";
+
+			operating-points = <
+				1200000 1250000
+				1000000 1150000
+				800000	1075000
+				500000	975000
+				400000	975000
+				200000	950000
+			>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+		};
+	};
+
 	gic: interrupt-controller@10490000 {
 		cpu-offset = <0x8000>;
 	};
@@ -73,6 +100,14 @@
 		compatible = "samsung,exynos4210-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1200000 3 7 3 4 1 7 5 0>,
+					       <1000000 3 7 3 4 1 7 4 0>,
+					       < 800000 3 7 3 3 1 7 3 0>,
+					       < 500000 3 7 3 3 1 7 3 0>,
+					       < 400000 3 7 3 3 1 7 3 0>,
+					       < 200000 1 3 1 1 1 0 3 0>;
 	};
 
 	pmu {
diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
index 94a43f9..efa8f25 100644
--- a/arch/arm/boot/dts/exynos4212.dtsi
+++ b/arch/arm/boot/dts/exynos4212.dtsi
@@ -22,6 +22,24 @@
 / {
 	compatible = "samsung,exynos4212";
 
+	clock: clock-controller@10030000 {
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1500000 3 7 0 6 1 2 6 0>,
+					       <1400000 3 7 0 6 1 2 6 0>,
+					       <1300000 3 7 0 5 1 2 5 0>,
+					       <1200000 3 7 0 5 1 2 5 0>,
+					       <1100000 3 6 0 4 1 2 4 0>,
+					       <1000000 2 5 0 4 1 1 4 0>,
+					       < 900000 2 5 0 3 1 1 3 0>,
+					       < 800000 2 5 0 3 1 1 3 0>,
+					       < 700000 2 4 0 3 1 1 3 0>,
+					       < 600000 2 4 0 3 1 1 3 0>,
+					       < 500000 2 4 0 3 1 1 3 0>,
+					       < 400000 2 4 0 3 1 1 3 0>,
+					       < 300000 2 4 0 2 1 1 3 0>,
+					       < 200000 1 3 0 1 1 1 3 0>;
+	};
+
 	gic: interrupt-controller@10490000 {
 		cpu-offset = <0x8000>;
 	};
diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts
index 9804fcb..04c14dc 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@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 6bc0539..89bcf2c 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@0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	firmware@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@0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	firmware@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..f7efdbb 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -22,6 +22,37 @@
 / {
 	compatible = "samsung,exynos4412";
 
+	cpus {
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <2>;
+		};
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <3>;
+		};
+	};
+
+	clock: clock-controller@10030000 {
+		samsung,armclk-cells = <10>;
+		samsung,armclk-divider-table = <1500000 3 7 0 6 1 2 6 0 7>,
+					       <1400000 3 7 0 6 1 2 6 0 6>,
+					       <1300000 3 7 0 5 1 2 5 0 6>,
+					       <1200000 3 7 0 5 1 2 5 0 5>,
+					       <1100000 3 6 0 4 1 2 4 0 5>,
+					       <1000000 2 5 0 4 1 1 4 0 4>,
+					       < 900000 2 5 0 3 1 1 3 0 4>,
+					       < 800000 2 5 0 3 1 1 3 0 3>,
+					       < 700000 2 4 0 3 1 1 3 0 3>,
+					       < 600000 2 4 0 3 1 1 3 0 2>,
+					       < 500000 2 4 0 3 1 1 3 0 2>,
+					       < 400000 2 4 0 3 1 1 3 0 1>,
+					       < 300000 2 4 0 2 1 1 3 0 1>,
+					       < 200000 1 3 0 1 1 1 3 0 0>;
+	};
+
 	gic: interrupt-controller@10490000 {
 		cpu-offset = <0x4000>;
 	};
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 5c412aa..c613fc2 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -31,6 +31,42 @@
 		mshc0 = &mshc_0;
 	};
 
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			clocks = <&clock 12>;
+			clock-names = "cpu";
+
+			operating-points = <
+				1500000 1350000
+				1400000 1287500
+				1300000 1250000
+				1200000 1187500
+				1100000 1137500
+				1000000 1087500
+				 900000 1037500
+				 800000 1000000
+				 700000  987500
+				 600000  975000
+				 500000  950000
+				 400000  925000
+				 300000  900000
+				 200000  900000
+			>;
+			clock-latency = <200000>;
+			boost-frequency = <1500000 1350000>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+		};
+	};
+
 	pd_isp: isp-power-domain@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@0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	codec@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@0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	pinctrl@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 3e69837..6ce964f 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@0 {
+			cpu0-supply = <&buck2_reg>;
+		};
+	};
+
 	i2c@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..0a8545e 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -61,6 +61,29 @@
 			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>;
 		};
 		cpu@1 {
 			device_type = "cpu";
@@ -84,6 +107,24 @@
 		compatible = "samsung,exynos5250-clock";
 		reg = <0x10010000 0x30000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1700000 3 7 7 7 3 5 0 2>,
+					       <1600000 3 7 7 7 1 4 0 2>,
+					       <1500000 2 7 7 7 1 4 0 2>,
+					       <1400000 2 7 7 6 1 4 0 2>,
+					       <1300000 2 7 7 6 1 3 0 2>,
+					       <1200000 2 7 7 5 1 3 0 2>,
+					       <1100000 3 7 7 5 1 3 0 2>,
+					       <1000000 1 7 7 4 1 2 0 2>,
+					       < 900000 1 7 7 4 1 2 0 2>,
+					       < 800000 1 7 7 4 1 2 0 2>,
+					       < 700000 1 7 7 3 1 1 0 2>,
+					       < 600000 1 7 7 3 1 1 0 2>,
+					       < 500000 1 7 7 2 1 1 0 2>,
+					       < 400000 1 7 7 2 1 1 0 2>,
+					       < 300000 1 7 7 1 1 1 0 2>,
+					       < 200000 1 7 7 1 1 1 0 2>;
 	};
 
 	clock_audss: audss-clock-controller@3810000 {
-- 
1.7.10.4


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

* [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 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 data for migrating from Exynos specific cpufreq driver to using
generic cpufreq-cpu0 driver.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 .../devicetree/bindings/clock/exynos5250-clock.txt |    1 +
 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                  |   18 +++++++++
 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                  |   31 +++++++++++++++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   36 +++++++++++++++++
 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                  |   41 ++++++++++++++++++++
 15 files changed, 216 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 9ca818e..4513cbb 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -43,6 +43,7 @@ clock which they consume.
   ----------------------------
 
   fin_pll		1
+  armclk		12
 
   [Clock Gate for Special Clocks]
 
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..25487d76 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..a774247 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -36,6 +36,33 @@
 		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 = <
+				1200000 1250000
+				1000000 1150000
+				800000	1075000
+				500000	975000
+				400000	975000
+				200000	950000
+			>;
+		};
+
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+		};
+	};
+
 	gic: interrupt-controller at 10490000 {
 		cpu-offset = <0x8000>;
 	};
@@ -73,6 +100,14 @@
 		compatible = "samsung,exynos4210-clock";
 		reg = <0x10030000 0x20000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1200000 3 7 3 4 1 7 5 0>,
+					       <1000000 3 7 3 4 1 7 4 0>,
+					       < 800000 3 7 3 3 1 7 3 0>,
+					       < 500000 3 7 3 3 1 7 3 0>,
+					       < 400000 3 7 3 3 1 7 3 0>,
+					       < 200000 1 3 1 1 1 0 3 0>;
 	};
 
 	pmu {
diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
index 94a43f9..efa8f25 100644
--- a/arch/arm/boot/dts/exynos4212.dtsi
+++ b/arch/arm/boot/dts/exynos4212.dtsi
@@ -22,6 +22,24 @@
 / {
 	compatible = "samsung,exynos4212";
 
+	clock: clock-controller at 10030000 {
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1500000 3 7 0 6 1 2 6 0>,
+					       <1400000 3 7 0 6 1 2 6 0>,
+					       <1300000 3 7 0 5 1 2 5 0>,
+					       <1200000 3 7 0 5 1 2 5 0>,
+					       <1100000 3 6 0 4 1 2 4 0>,
+					       <1000000 2 5 0 4 1 1 4 0>,
+					       < 900000 2 5 0 3 1 1 3 0>,
+					       < 800000 2 5 0 3 1 1 3 0>,
+					       < 700000 2 4 0 3 1 1 3 0>,
+					       < 600000 2 4 0 3 1 1 3 0>,
+					       < 500000 2 4 0 3 1 1 3 0>,
+					       < 400000 2 4 0 3 1 1 3 0>,
+					       < 300000 2 4 0 2 1 1 3 0>,
+					       < 200000 1 3 0 1 1 1 3 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 9804fcb..04c14dc 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 6bc0539..89bcf2c 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..f7efdbb 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -22,6 +22,37 @@
 / {
 	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 {
+		samsung,armclk-cells = <10>;
+		samsung,armclk-divider-table = <1500000 3 7 0 6 1 2 6 0 7>,
+					       <1400000 3 7 0 6 1 2 6 0 6>,
+					       <1300000 3 7 0 5 1 2 5 0 6>,
+					       <1200000 3 7 0 5 1 2 5 0 5>,
+					       <1100000 3 6 0 4 1 2 4 0 5>,
+					       <1000000 2 5 0 4 1 1 4 0 4>,
+					       < 900000 2 5 0 3 1 1 3 0 4>,
+					       < 800000 2 5 0 3 1 1 3 0 3>,
+					       < 700000 2 4 0 3 1 1 3 0 3>,
+					       < 600000 2 4 0 3 1 1 3 0 2>,
+					       < 500000 2 4 0 3 1 1 3 0 2>,
+					       < 400000 2 4 0 3 1 1 3 0 1>,
+					       < 300000 2 4 0 2 1 1 3 0 1>,
+					       < 200000 1 3 0 1 1 1 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..c613fc2 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -31,6 +31,42 @@
 		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 = <
+				1500000 1350000
+				1400000 1287500
+				1300000 1250000
+				1200000 1187500
+				1100000 1137500
+				1000000 1087500
+				 900000 1037500
+				 800000 1000000
+				 700000  987500
+				 600000  975000
+				 500000  950000
+				 400000  925000
+				 300000  900000
+				 200000  900000
+			>;
+			clock-latency = <200000>;
+			boost-frequency = <1500000 1350000>;
+		};
+		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 3e69837..6ce964f 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..0a8545e 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -61,6 +61,29 @@
 			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>;
 		};
 		cpu at 1 {
 			device_type = "cpu";
@@ -84,6 +107,24 @@
 		compatible = "samsung,exynos5250-clock";
 		reg = <0x10010000 0x30000>;
 		#clock-cells = <1>;
+
+		samsung,armclk-cells = <9>;
+		samsung,armclk-divider-table = <1700000 3 7 7 7 3 5 0 2>,
+					       <1600000 3 7 7 7 1 4 0 2>,
+					       <1500000 2 7 7 7 1 4 0 2>,
+					       <1400000 2 7 7 6 1 4 0 2>,
+					       <1300000 2 7 7 6 1 3 0 2>,
+					       <1200000 2 7 7 5 1 3 0 2>,
+					       <1100000 3 7 7 5 1 3 0 2>,
+					       <1000000 1 7 7 4 1 2 0 2>,
+					       < 900000 1 7 7 4 1 2 0 2>,
+					       < 800000 1 7 7 4 1 2 0 2>,
+					       < 700000 1 7 7 3 1 1 0 2>,
+					       < 600000 1 7 7 3 1 1 0 2>,
+					       < 500000 1 7 7 2 1 1 0 2>,
+					       < 400000 1 7 7 2 1 1 0 2>,
+					       < 300000 1 7 7 1 1 1 0 2>,
+					       < 200000 1 7 7 1 1 1 0 2>;
 	};
 
 	clock_audss: audss-clock-controller at 3810000 {
-- 
1.7.10.4

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

* [PATCH v3 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

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.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Reviewed-by: Lukasz Majewski <l.majewski@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.7.10.4


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

* [PATCH v3 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 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.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Reviewed-by: Lukasz Majewski <l.majewski@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.7.10.4

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

* [PATCH v3 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
  2014-02-07 15:55 ` Thomas Abraham
@ 2014-02-07 15:55   ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 UTC (permalink / raw)
  To: cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, t.figa,
	l.majewski, viresh.kumar, thomas.ab, heiko

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.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 drivers/cpufreq/Kconfig.arm          |   51 ------
 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, 989 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..38f691a 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
@@ -66,21 +30,6 @@ config ARM_EXYNOS5440_CPUFREQ
 
 	  If in doubt, say N.
 
-config ARM_EXYNOS_CPU_FREQ_BOOST_SW
-	bool "EXYNOS Frequency Overclocking - Software"
-	depends on ARM_EXYNOS_CPUFREQ
-	select CPU_FREQ_BOOST_SW
-	select EXYNOS_THERMAL
-	help
-	  This driver supports software managed overclocking (BOOST).
-	  It allows usage of special frequencies for Samsung Exynos
-	  processors if thermal conditions are appropriate.
-
-	  It reguires, for safe operation, thermal framework with properly
-	  defined trip points.
-
-	  If in doubt, say N.
-
 config ARM_HIGHBANK_CPUFREQ
 	tristate "Calxeda Highbank-based"
 	depends on ARCH_HIGHBANK
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.7.10.4


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

* [PATCH v3 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support
@ 2014-02-07 15:55   ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-07 15:55 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.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
---
 drivers/cpufreq/Kconfig.arm          |   51 ------
 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, 989 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..38f691a 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
@@ -66,21 +30,6 @@ config ARM_EXYNOS5440_CPUFREQ
 
 	  If in doubt, say N.
 
-config ARM_EXYNOS_CPU_FREQ_BOOST_SW
-	bool "EXYNOS Frequency Overclocking - Software"
-	depends on ARM_EXYNOS_CPUFREQ
-	select CPU_FREQ_BOOST_SW
-	select EXYNOS_THERMAL
-	help
-	  This driver supports software managed overclocking (BOOST).
-	  It allows usage of special frequencies for Samsung Exynos
-	  processors if thermal conditions are appropriate.
-
-	  It reguires, for safe operation, thermal framework with properly
-	  defined trip points.
-
-	  If in doubt, say N.
-
 config ARM_HIGHBANK_CPUFREQ
 	tristate "Calxeda Highbank-based"
 	depends on ARCH_HIGHBANK
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.7.10.4

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-07 15:55   ` Thomas Abraham
@ 2014-02-07 16:16     ` Nishanth Menon
  -1 siblings, 0 replies; 43+ messages in thread
From: Nishanth Menon @ 2014-02-07 16:16 UTC (permalink / raw)
  To: Thomas Abraham, cpufreq, linux-arm-kernel
  Cc: l.majewski, kgene.kim, mturquette, heiko, viresh.kumar, t.figa,
	linux-samsung-soc, thomas.ab, shawn.guo

On 02/07/2014 09:55 AM, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> Lookup for the optional boost-frequency property in cpu0 node and if
> available, enable support for boost mode frequencies. The frequencies
> usable in boost mode are determined while preparing the cpufreq table
> from the list of operating points available.
> 
> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
> this driver by default. On platforms that do not support boost mode,
> the boost mode frequencies will not be specified in cpu0 node and
> hence the boost mode support will not be enabled. Since this driver
> anyways depends on THERMAL config option, it is safe to enable
> CPU_FREQ_BOOST_SW config option as default.
> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>  drivers/cpufreq/Kconfig                                    |    1 +
>  drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>  3 files changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> index f055515..60f321a 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> @@ -19,6 +19,8 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
> +- boost-frequency:
> +     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>  
>  Examples:
>  
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 4b029c0..52cc704 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>  	tristate "Generic CPU0 cpufreq driver"
>  	depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>  	select PM_OPP
> +	select CPU_FREQ_BOOST_SW
>  	help
>  	  This adds a generic cpufreq driver for CPU0 frequency management.
>  	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index 0c12ffc..06539eb 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>  			transition_latency += ret * 1000;
>  	}
>  
> +	if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
> +		cpu0_cpufreq_driver.boost_supported = true;
> +
>  	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>  	if (ret) {
>  		pr_err("failed register driver: %d\n", ret);
> 

might as well hide that under the opp api which returns a bool that
says if boost is supported or not. that allows the parse to be
isolated to a single location.

-- 
Regards,
Nishanth Menon

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-07 16:16     ` Nishanth Menon
  0 siblings, 0 replies; 43+ messages in thread
From: Nishanth Menon @ 2014-02-07 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/07/2014 09:55 AM, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> Lookup for the optional boost-frequency property in cpu0 node and if
> available, enable support for boost mode frequencies. The frequencies
> usable in boost mode are determined while preparing the cpufreq table
> from the list of operating points available.
> 
> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
> this driver by default. On platforms that do not support boost mode,
> the boost mode frequencies will not be specified in cpu0 node and
> hence the boost mode support will not be enabled. Since this driver
> anyways depends on THERMAL config option, it is safe to enable
> CPU_FREQ_BOOST_SW config option as default.
> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>  drivers/cpufreq/Kconfig                                    |    1 +
>  drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>  3 files changed, 6 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> index f055515..60f321a 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> @@ -19,6 +19,8 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
> +- boost-frequency:
> +     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>  
>  Examples:
>  
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 4b029c0..52cc704 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>  	tristate "Generic CPU0 cpufreq driver"
>  	depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>  	select PM_OPP
> +	select CPU_FREQ_BOOST_SW
>  	help
>  	  This adds a generic cpufreq driver for CPU0 frequency management.
>  	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index 0c12ffc..06539eb 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>  			transition_latency += ret * 1000;
>  	}
>  
> +	if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
> +		cpu0_cpufreq_driver.boost_supported = true;
> +
>  	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>  	if (ret) {
>  		pr_err("failed register driver: %d\n", ret);
> 

might as well hide that under the opp api which returns a bool that
says if boost is supported or not. that allows the parse to be
isolated to a single location.

-- 
Regards,
Nishanth Menon

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

* Re: [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data
  2014-02-07 15:55   ` Thomas Abraham
@ 2014-02-07 16:20     ` Sudeep Holla
  -1 siblings, 0 replies; 43+ messages in thread
From: Sudeep Holla @ 2014-02-07 16:20 UTC (permalink / raw)
  To: Thomas Abraham, cpufreq, linux-arm-kernel
  Cc: Sudeep.Holla, l.majewski, kgene.kim, mturquette, heiko,
	viresh.kumar, t.figa, linux-samsung-soc, thomas.ab, shawn.guo

On 07/02/14 15:55, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> For all Exynos based platforms, add CPU nodes, operating points and cpu
> clock data for migrating from Exynos specific cpufreq driver to using
> generic cpufreq-cpu0 driver.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>

[...]

> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
> index 5c412aa..c613fc2 100644
> --- a/arch/arm/boot/dts/exynos4x12.dtsi
> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
> @@ -31,6 +31,42 @@
>                 mshc0 = &mshc_0;
>         };
> 
> +       cpus {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               cpu@0 {
> +                       device_type = "cpu";
> +                       compatible = "arm,cortex-a9";
> +                       reg = <0>;
> +                       clocks = <&clock 12>;
> +                       clock-names = "cpu";
> +
> +                       operating-points = <
> +                               1500000 1350000
> +                               1400000 1287500
> +                               1300000 1250000
> +                               1200000 1187500
> +                               1100000 1137500
> +                               1000000 1087500
> +                                900000 1037500
> +                                800000 1000000
> +                                700000  987500
> +                                600000  975000
> +                                500000  950000
> +                                400000  925000
> +                                300000  900000
> +                                200000  900000
> +                       >;
> +                       clock-latency = <200000>;
> +                       boost-frequency = <1500000 1350000>;

This is confusing, 1350000 is not in the OPP frequency list or this is still
following old binding with voltage. Either case this needs to be fixed.

Regards,
Sudeep


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

* [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data
@ 2014-02-07 16:20     ` Sudeep Holla
  0 siblings, 0 replies; 43+ messages in thread
From: Sudeep Holla @ 2014-02-07 16:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/02/14 15:55, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> For all Exynos based platforms, add CPU nodes, operating points and cpu
> clock data for migrating from Exynos specific cpufreq driver to using
> generic cpufreq-cpu0 driver.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>

[...]

> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
> index 5c412aa..c613fc2 100644
> --- a/arch/arm/boot/dts/exynos4x12.dtsi
> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
> @@ -31,6 +31,42 @@
>                 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 = <
> +                               1500000 1350000
> +                               1400000 1287500
> +                               1300000 1250000
> +                               1200000 1187500
> +                               1100000 1137500
> +                               1000000 1087500
> +                                900000 1037500
> +                                800000 1000000
> +                                700000  987500
> +                                600000  975000
> +                                500000  950000
> +                                400000  925000
> +                                300000  900000
> +                                200000  900000
> +                       >;
> +                       clock-latency = <200000>;
> +                       boost-frequency = <1500000 1350000>;

This is confusing, 1350000 is not in the OPP frequency list or this is still
following old binding with voltage. Either case this needs to be fixed.

Regards,
Sudeep

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-07 16:16     ` Nishanth Menon
@ 2014-02-08  5:19       ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-08  5:19 UTC (permalink / raw)
  To: Nishanth Menon
  Cc: cpufreq, linux-arm-kernel, Lukasz Majewski, Kukjin Kim,
	Mike Turquette, Heiko Stübner, Viresh Kumar, Tomasz Figa,
	linux-samsung-soc, thomas.ab, Shawn Guo

On Fri, Feb 7, 2014 at 9:46 PM, Nishanth Menon <nm@ti.com> wrote:
> On 02/07/2014 09:55 AM, Thomas Abraham wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> Lookup for the optional boost-frequency property in cpu0 node and if
>> available, enable support for boost mode frequencies. The frequencies
>> usable in boost mode are determined while preparing the cpufreq table
>> from the list of operating points available.
>>
>> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
>> this driver by default. On platforms that do not support boost mode,
>> the boost mode frequencies will not be specified in cpu0 node and
>> hence the boost mode support will not be enabled. Since this driver
>> anyways depends on THERMAL config option, it is safe to enable
>> CPU_FREQ_BOOST_SW config option as default.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Cc: Lukasz Majewski <l.majewski@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>>  drivers/cpufreq/Kconfig                                    |    1 +
>>  drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>>  3 files changed, 6 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..60f321a 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,8 @@ Optional properties:
>>  - cooling-min-level:
>>  - cooling-max-level:
>>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- boost-frequency:
>> +     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>>
>>  Examples:
>>
>> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>> index 4b029c0..52cc704 100644
>> --- a/drivers/cpufreq/Kconfig
>> +++ b/drivers/cpufreq/Kconfig
>> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>>       tristate "Generic CPU0 cpufreq driver"
>>       depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>>       select PM_OPP
>> +     select CPU_FREQ_BOOST_SW
>>       help
>>         This adds a generic cpufreq driver for CPU0 frequency management.
>>         It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..06539eb 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>                       transition_latency += ret * 1000;
>>       }
>>
>> +     if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>> +             cpu0_cpufreq_driver.boost_supported = true;
>> +
>>       ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>>       if (ret) {
>>               pr_err("failed register driver: %d\n", ret);
>>
>
> might as well hide that under the opp api which returns a bool that
> says if boost is supported or not. that allows the parse to be
> isolated to a single location.

This is specific to the cpufreq-cpu0 driver. Other cpufreq drivers
might want to use other methods and additional constraints to
determine if boost has to be enabled.

Thanks,
Thomas.

>
> --
> Regards,
> Nishanth Menon

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-08  5:19       ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-08  5:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 7, 2014 at 9:46 PM, Nishanth Menon <nm@ti.com> wrote:
> On 02/07/2014 09:55 AM, Thomas Abraham wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> Lookup for the optional boost-frequency property in cpu0 node and if
>> available, enable support for boost mode frequencies. The frequencies
>> usable in boost mode are determined while preparing the cpufreq table
>> from the list of operating points available.
>>
>> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
>> this driver by default. On platforms that do not support boost mode,
>> the boost mode frequencies will not be specified in cpu0 node and
>> hence the boost mode support will not be enabled. Since this driver
>> anyways depends on THERMAL config option, it is safe to enable
>> CPU_FREQ_BOOST_SW config option as default.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Cc: Lukasz Majewski <l.majewski@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>  Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>>  drivers/cpufreq/Kconfig                                    |    1 +
>>  drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>>  3 files changed, 6 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..60f321a 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,8 @@ Optional properties:
>>  - cooling-min-level:
>>  - cooling-max-level:
>>       Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- boost-frequency:
>> +     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>>
>>  Examples:
>>
>> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>> index 4b029c0..52cc704 100644
>> --- a/drivers/cpufreq/Kconfig
>> +++ b/drivers/cpufreq/Kconfig
>> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>>       tristate "Generic CPU0 cpufreq driver"
>>       depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>>       select PM_OPP
>> +     select CPU_FREQ_BOOST_SW
>>       help
>>         This adds a generic cpufreq driver for CPU0 frequency management.
>>         It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..06539eb 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>                       transition_latency += ret * 1000;
>>       }
>>
>> +     if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>> +             cpu0_cpufreq_driver.boost_supported = true;
>> +
>>       ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>>       if (ret) {
>>               pr_err("failed register driver: %d\n", ret);
>>
>
> might as well hide that under the opp api which returns a bool that
> says if boost is supported or not. that allows the parse to be
> isolated to a single location.

This is specific to the cpufreq-cpu0 driver. Other cpufreq drivers
might want to use other methods and additional constraints to
determine if boost has to be enabled.

Thanks,
Thomas.

>
> --
> Regards,
> Nishanth Menon

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

* Re: [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data
  2014-02-07 16:20     ` Sudeep Holla
@ 2014-02-08  5:20       ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-08  5:20 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: cpufreq, linux-arm-kernel, l.majewski, kgene.kim, mturquette,
	heiko, viresh.kumar, t.figa, linux-samsung-soc, thomas.ab,
	shawn.guo

On Fri, Feb 7, 2014 at 9:50 PM, Sudeep Holla <Sudeep.Holla@arm.com> wrote:
> On 07/02/14 15:55, Thomas Abraham wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> For all Exynos based platforms, add CPU nodes, operating points and cpu
>> clock data for migrating from Exynos specific cpufreq driver to using
>> generic cpufreq-cpu0 driver.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>
> [...]
>
>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>> index 5c412aa..c613fc2 100644
>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>> @@ -31,6 +31,42 @@
>>                 mshc0 = &mshc_0;
>>         };
>>
>> +       cpus {
>> +               #address-cells = <1>;
>> +               #size-cells = <0>;
>> +               cpu@0 {
>> +                       device_type = "cpu";
>> +                       compatible = "arm,cortex-a9";
>> +                       reg = <0>;
>> +                       clocks = <&clock 12>;
>> +                       clock-names = "cpu";
>> +
>> +                       operating-points = <
>> +                               1500000 1350000
>> +                               1400000 1287500
>> +                               1300000 1250000
>> +                               1200000 1187500
>> +                               1100000 1137500
>> +                               1000000 1087500
>> +                                900000 1037500
>> +                                800000 1000000
>> +                                700000  987500
>> +                                600000  975000
>> +                                500000  950000
>> +                                400000  925000
>> +                                300000  900000
>> +                                200000  900000
>> +                       >;
>> +                       clock-latency = <200000>;
>> +                       boost-frequency = <1500000 1350000>;
>
> This is confusing, 1350000 is not in the OPP frequency list or this is still
> following old binding with voltage. Either case this needs to be fixed.

Yes, I missed that. Will fix it. Thanks for your review.

Regards,
Thomas.


>
> Regards,
> Sudeep
>

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

* [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data
@ 2014-02-08  5:20       ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-08  5:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 7, 2014 at 9:50 PM, Sudeep Holla <Sudeep.Holla@arm.com> wrote:
> On 07/02/14 15:55, Thomas Abraham wrote:
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> For all Exynos based platforms, add CPU nodes, operating points and cpu
>> clock data for migrating from Exynos specific cpufreq driver to using
>> generic cpufreq-cpu0 driver.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>
> [...]
>
>> diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
>> index 5c412aa..c613fc2 100644
>> --- a/arch/arm/boot/dts/exynos4x12.dtsi
>> +++ b/arch/arm/boot/dts/exynos4x12.dtsi
>> @@ -31,6 +31,42 @@
>>                 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 = <
>> +                               1500000 1350000
>> +                               1400000 1287500
>> +                               1300000 1250000
>> +                               1200000 1187500
>> +                               1100000 1137500
>> +                               1000000 1087500
>> +                                900000 1037500
>> +                                800000 1000000
>> +                                700000  987500
>> +                                600000  975000
>> +                                500000  950000
>> +                                400000  925000
>> +                                300000  900000
>> +                                200000  900000
>> +                       >;
>> +                       clock-latency = <200000>;
>> +                       boost-frequency = <1500000 1350000>;
>
> This is confusing, 1350000 is not in the OPP frequency list or this is still
> following old binding with voltage. Either case this needs to be fixed.

Yes, I missed that. Will fix it. Thanks for your review.

Regards,
Thomas.


>
> Regards,
> Sudeep
>

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-08  5:19       ` Thomas Abraham
@ 2014-02-08 16:31         ` Nishanth Menon
  -1 siblings, 0 replies; 43+ messages in thread
From: Nishanth Menon @ 2014-02-08 16:31 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: Lukasz Majewski, Kukjin Kim, Mike Turquette, Heiko Stübner,
	Viresh Kumar, Tomasz Figa, cpufreq, linux-samsung-soc, thomas.ab,
	Shawn Guo, linux-arm-kernel

On Fri, Feb 7, 2014 at 11:19 PM, Thomas Abraham <ta.omasab@gmail.com> wrote:
>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>                       transition_latency += ret * 1000;
>>>       }
>>>
>>> +     if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>>> +             cpu0_cpufreq_driver.boost_supported = true;
>>> +
>> might as well hide that under the opp api which returns a bool that
>> says if boost is supported or not. that allows the parse to be
>> isolated to a single location.
>
> This is specific to the cpufreq-cpu0 driver. Other cpufreq drivers
> might want to use other methods and additional constraints to
> determine if boost has to be enabled.

struct cpufreq_driver::boost_supported is nothing CPU0 specifc - i am
just saying that the same property "boost-frequency" parsed by in two
places (dev_pm_opp_init_cpufreq_table and cpu0_cpufreq_probe) is a
very bad idea.

you could instead make
int dev_pm_opp_init_cpufreq_table(struct device *dev,
                           struct cpufreq_frequency_table **table)
into:
int dev_pm_opp_init_cpufreq_table(struct device *dev,
                           struct cpufreq_frequency_table **table,
bool *boost_supported);

Then use boost_supported for anything of your driver's choice
(including updating cpufreq_driver::boost_supported).

That allows the property to be isolated into a single function, who
can be modified without impacting other drivers at a later point in
time.

Regards,
Nishanth Menon

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-08 16:31         ` Nishanth Menon
  0 siblings, 0 replies; 43+ messages in thread
From: Nishanth Menon @ 2014-02-08 16:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 7, 2014 at 11:19 PM, Thomas Abraham <ta.omasab@gmail.com> wrote:
>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>>>                       transition_latency += ret * 1000;
>>>       }
>>>
>>> +     if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>>> +             cpu0_cpufreq_driver.boost_supported = true;
>>> +
>> might as well hide that under the opp api which returns a bool that
>> says if boost is supported or not. that allows the parse to be
>> isolated to a single location.
>
> This is specific to the cpufreq-cpu0 driver. Other cpufreq drivers
> might want to use other methods and additional constraints to
> determine if boost has to be enabled.

struct cpufreq_driver::boost_supported is nothing CPU0 specifc - i am
just saying that the same property "boost-frequency" parsed by in two
places (dev_pm_opp_init_cpufreq_table and cpu0_cpufreq_probe) is a
very bad idea.

you could instead make
int dev_pm_opp_init_cpufreq_table(struct device *dev,
                           struct cpufreq_frequency_table **table)
into:
int dev_pm_opp_init_cpufreq_table(struct device *dev,
                           struct cpufreq_frequency_table **table,
bool *boost_supported);

Then use boost_supported for anything of your driver's choice
(including updating cpufreq_driver::boost_supported).

That allows the property to be isolated into a single function, who
can be modified without impacting other drivers at a later point in
time.

Regards,
Nishanth Menon

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-07 15:55   ` Thomas Abraham
@ 2014-02-10  8:20     ` Lukasz Majewski
  -1 siblings, 0 replies; 43+ messages in thread
From: Lukasz Majewski @ 2014-02-10  8:20 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: cpufreq, linux-arm-kernel, linux-samsung-soc, mturquette,
	shawn.guo, kgene.kim, t.figa, viresh.kumar, thomas.ab, heiko

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> Lookup for the optional boost-frequency property in cpu0 node and if
> available, enable support for boost mode frequencies. The frequencies
> usable in boost mode are determined while preparing the cpufreq table
> from the list of operating points available.
> 
> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
> this driver by default. On platforms that do not support boost mode,
> the boost mode frequencies will not be specified in cpu0 node and
> hence the boost mode support will not be enabled. Since this driver
> anyways depends on THERMAL config option, it is safe to enable
> CPU_FREQ_BOOST_SW config option as default.

I think that you introduce some implicit dependency here.

I don't like the idea to enable CPU_FREQ_BOOST_SW by default and depend
on other option (THERMAL in this case).
 
I think that user shall feel free to explicitly enable or disable boost
from menuconfig.

> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>  drivers/cpufreq/Kconfig                                    |    1 +
>  drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>  3 files changed, 6 insertions(+)
> 
> diff --git
> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
> f055515..60f321a 100644 ---
> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@ -19,6
> +19,8 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to
> Documentation/devicetree/bindings/thermal/thermal.txt. +-
> boost-frequency:
> +     Please refer to
> Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt 
>  Examples:
>  
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 4b029c0..52cc704 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>  	tristate "Generic CPU0 cpufreq driver"
>  	depends on HAVE_CLK && REGULATOR && OF && THERMAL &&
> CPU_THERMAL select PM_OPP
> +	select CPU_FREQ_BOOST_SW
>  	help
>  	  This adds a generic cpufreq driver for CPU0 frequency
> management. It supports both uniprocessor (UP) and symmetric
> multiprocessor (SMP) diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..06539eb 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct
> platform_device *pdev) transition_latency += ret * 1000;
>  	}
>  
> +	if (of_find_property(cpu_dev->of_node, "boost-frequency",
> NULL))
> +		cpu0_cpufreq_driver.boost_supported = true;
> +

This is also a bit misleading. Here you assume, that boost is supported
when somebody define "boost-frequency" DTS attribute. Conceptually the
boost is supported when user explicitly selects
CONFIG_CPU_FREQ_BOOST_SW.


I would prefer to see approach similar to the one now found at
exynos-cpufreq.c exynos_driver struct:

static struct cpufreq_driver cpu0_cpufreq_driver = {
	.flags = CPUFREQ_STICKY,
	.verify = cpu0_verify_speed,
	.target = cpu0_set_target,
	.get = cpu0_get_speed,
#ifdef CONFIG_CPU_FREQ_BOOST_SW
	.boost_supported = true,
#endif
	... other fields ...

and also, please remove references to
CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW flag since it will not be used
after the exynos cpufreq clean up.

>  	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>  	if (ret) {
>  		pr_err("failed register driver: %d\n", ret);


-- 
Best regards,

Lukasz Majewski

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

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-10  8:20     ` Lukasz Majewski
  0 siblings, 0 replies; 43+ messages in thread
From: Lukasz Majewski @ 2014-02-10  8:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

> From: Thomas Abraham <thomas.ab@samsung.com>
> 
> Lookup for the optional boost-frequency property in cpu0 node and if
> available, enable support for boost mode frequencies. The frequencies
> usable in boost mode are determined while preparing the cpufreq table
> from the list of operating points available.
> 
> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
> this driver by default. On platforms that do not support boost mode,
> the boost mode frequencies will not be specified in cpu0 node and
> hence the boost mode support will not be enabled. Since this driver
> anyways depends on THERMAL config option, it is safe to enable
> CPU_FREQ_BOOST_SW config option as default.

I think that you introduce some implicit dependency here.

I don't like the idea to enable CPU_FREQ_BOOST_SW by default and depend
on other option (THERMAL in this case).
 
I think that user shall feel free to explicitly enable or disable boost
from menuconfig.

> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>  drivers/cpufreq/Kconfig                                    |    1 +
>  drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>  3 files changed, 6 insertions(+)
> 
> diff --git
> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
> f055515..60f321a 100644 ---
> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@ -19,6
> +19,8 @@ Optional properties:
>  - cooling-min-level:
>  - cooling-max-level:
>       Please refer to
> Documentation/devicetree/bindings/thermal/thermal.txt. +-
> boost-frequency:
> +     Please refer to
> Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt 
>  Examples:
>  
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 4b029c0..52cc704 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>  	tristate "Generic CPU0 cpufreq driver"
>  	depends on HAVE_CLK && REGULATOR && OF && THERMAL &&
> CPU_THERMAL select PM_OPP
> +	select CPU_FREQ_BOOST_SW
>  	help
>  	  This adds a generic cpufreq driver for CPU0 frequency
> management. It supports both uniprocessor (UP) and symmetric
> multiprocessor (SMP) diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..06539eb 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct
> platform_device *pdev) transition_latency += ret * 1000;
>  	}
>  
> +	if (of_find_property(cpu_dev->of_node, "boost-frequency",
> NULL))
> +		cpu0_cpufreq_driver.boost_supported = true;
> +

This is also a bit misleading. Here you assume, that boost is supported
when somebody define "boost-frequency" DTS attribute. Conceptually the
boost is supported when user explicitly selects
CONFIG_CPU_FREQ_BOOST_SW.


I would prefer to see approach similar to the one now found at
exynos-cpufreq.c exynos_driver struct:

static struct cpufreq_driver cpu0_cpufreq_driver = {
	.flags = CPUFREQ_STICKY,
	.verify = cpu0_verify_speed,
	.target = cpu0_set_target,
	.get = cpu0_get_speed,
#ifdef CONFIG_CPU_FREQ_BOOST_SW
	.boost_supported = true,
#endif
	... other fields ...

and also, please remove references to
CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW flag since it will not be used
after the exynos cpufreq clean up.

>  	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>  	if (ret) {
>  		pr_err("failed register driver: %d\n", ret);


-- 
Best regards,

Lukasz Majewski

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

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

* Re: [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-02-07 15:55   ` Thomas Abraham
@ 2014-02-10  9:00     ` Lukasz Majewski
  -1 siblings, 0 replies; 43+ messages in thread
From: Lukasz Majewski @ 2014-02-10  9:00 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: cpufreq, linux-arm-kernel, linux-samsung-soc, mturquette,
	shawn.guo, kgene.kim, t.figa, viresh.kumar, thomas.ab, heiko

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 configuration data for this clock is obtained from device tree.

I'm a bit confused with the sentence:

> This implementation is reusable for Exynos4x12 and Exynos5250 SoCs as
> well.

It seems that the implementation for Exynos4210 is already reused in
this code for Exynos4412. 

Is the name convention of exynos4210_* after the first SoC supporting
such setup? If yes, I think that it could be explicitly written in the
commit message.

Additionally, the above commit message could also emphasis, that the
implementation for other Exynos4 SoCs (like Exynos4412) is already
in place.


> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  drivers/clk/samsung/Makefile  |    2 +-
>  drivers/clk/samsung/clk-cpu.c |  409
> +++++++++++++++++++++++++++++++++++++++++
> drivers/clk/samsung/clk.h     |    5 + 3 files changed, 415
> insertions(+), 1 deletion(-) 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..673f620
> --- /dev/null
> +++ b/drivers/clk/samsung/clk-cpu.c
> @@ -0,0 +1,409 @@
> +/*
> + * 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
> +
> +#define MAX_DIV			8
> +
> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) +
> 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >>
> 28) & 0xf) + 1) +
> +#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1,
> d0)			\
> +		((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12)
> |	\
> +		 (d1 << 8) | (d0 <<  4))
> +#define EXYNOS4210_DIV_CPU1(d2, d1,
> d0)					\
> +		((d2 << 8) | (d1 << 4) | (d0 << 0))
> +
> +#define EXYNOS4210_DIV1_HPM_MASK	((0x7 << 0) | (0x7 << 4))
> +#define EXYNOS4210_MUX_HPM_MASK		(1 << 20)
> +
> +/**
> + * struct exynos4210_armclk_data: config data to setup exynos4210
> cpu clocks.
> + * @prate:	frequency of the parent clock.
> + * @div0:	value to be programmed in the div_cpu0 register.
> + * @div1:	value to be programmed in the div_cpu1 register.
> + *
> + * This structure holds the divider configuration data for divider
> clocks
> + * belonging to the CMU_CPU clock domain. The parent frequency at
> which these
> + * divider values are vaild is specified in @prate.
> + */
> +struct exynos4210_armclk_data {
> +	unsigned long	prate;
> +	unsigned int	div0;
> +	unsigned int	div1;
> +};
> +
> +/**
> + * struct samsung_cpuclk: information about clock supplied to a CPU
> core.
> + * @hw:		handle between ccf and cpu clock.
> + * @alt_parent:	alternate parent clock to use when switching
> the speed
> + *		of the primary parent 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.
> + * @clk_nb:	clock notifier registered for changes in clock
> speed of the
> + *		primary parent clock.
> + * @data:	optional data which the acutal instantiation of
> this clock
> + *		can use.
> + */
> +struct samsung_cpuclk {
> +	struct clk_hw		hw;
> +	struct clk		*alt_parent;
> +	void __iomem		*ctrl_base;
> +	unsigned long		offset;
> +	struct notifier_block	clk_nb;
> +	void			*data;
> +};
> +
> +#define to_samsung_cpuclk_hw(hw) container_of(hw, struct
> samsung_cpuclk, hw) +#define to_samsung_cpuclk_nb(nb)
> container_of(nb, struct samsung_cpuclk, clk_nb) +
> +/**
> + * struct samsung_cpuclk_soc_data: soc specific data for cpu clocks.
> + * @parser:	pointer to a function that can parse SoC specific
> data.
> + * @ops:	clock operations to be used for this clock.
> + * @offset:	optional offset from base of clock controller
> register base, to
> + *		be used when accessing clock controller registers
> related to the
> + *		cpu clock.
> + * @clk_cb:	the clock notifier callback to be called for
> changes in the
> + *		clock rate of the primary parent clock.
> + *
> + * This structure provides SoC specific data for ARM clocks. Based on
> + * the compatible value of the clock controller node, the value of
> the
> + * fields in this structure can be populated.
> + */
> +struct samsung_cpuclk_soc_data {
> +	int (*parser)(struct device_node *, void **);
> +	const struct clk_ops *ops;
> +	unsigned int offset;
> +	int (*clk_cb)(struct notifier_block *nb, unsigned long evt,
> void *data); +};
> +
> +/* common round rate callback useable for all types of cpu clocks */
> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	struct clk *parent = __clk_get_parent(hw->clk);
> +	unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
> +	unsigned long t_prate, best_div = 1;
> +	unsigned long delta, min_delta = UINT_MAX;
> +
> +	do {
> +		t_prate = __clk_round_rate(parent, drate * best_div);
> +		delta = drate - (t_prate / best_div);
> +		if (delta < min_delta) {
> +			*prate = t_prate;
> +			min_delta = delta;
> +		}
> +		if (!delta)
> +			break;
> +		best_div++;
> +	} while ((drate * best_div) < max_prate && best_div <=
> MAX_DIV); +
> +	return t_prate / best_div;
> +}
> +
> +static unsigned long _calc_div(unsigned long prate, unsigned long
> drate) +{
> +	unsigned long div = prate / drate;
> +
> +	WARN_ON(div >= MAX_DIV);
> +	return (!(prate % drate)) ? div-- : div;
> +}
> +
> +/* helper function to register a cpu clock */
> +static int __init samsung_cpuclk_register(unsigned int lookup_id,
> +		const char *name, const char **parents,
> +		unsigned int num_parents, void __iomem *base,
> +		const struct samsung_cpuclk_soc_data *soc_data,
> +		struct device_node *np, const struct clk_ops *ops)
> +{
> +	struct samsung_cpuclk *cpuclk;
> +	struct clk_init_data init;
> +	struct clk *clk;
> +	int ret;
> +
> +	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> +	if (!cpuclk) {
> +		pr_err("%s: could not allocate memory for %s
> clock\n",
> +					__func__, name);
> +		return -ENOMEM;
> +	}
> +
> +	init.name = name;
> +	init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
> +	init.parent_names = parents;
> +	init.num_parents = 1;
> +	init.ops = ops;
> +
> +	cpuclk->hw.init = &init;
> +	cpuclk->ctrl_base = base;
> +
> +	if (soc_data && soc_data->parser) {
> +		ret = soc_data->parser(np, &cpuclk->data);
> +		if (ret) {
> +			pr_err("%s: error %d in parsing %s clock
> data",
> +					__func__, ret, name);
> +			ret = -EINVAL;
> +			goto free_cpuclk;
> +		}
> +		cpuclk->offset = soc_data->offset;
> +		init.ops = soc_data->ops;
> +	}
> +
> +	if (soc_data && soc_data->clk_cb) {
> +		cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
> +		if (clk_notifier_register(__clk_lookup(parents[0]),
> +				&cpuclk->clk_nb)) {
> +			pr_err("%s: failed to register clock
> notifier for %s\n",
> +					__func__, name);
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	if (num_parents == 2) {
> +		cpuclk->alt_parent = __clk_lookup(parents[1]);
> +		if (!cpuclk->alt_parent) {
> +			pr_err("%s: could not lookup alternate
> parent %s\n",
> +					__func__, parents[1]);
> +			ret = -EINVAL;
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	clk = clk_register(NULL, &cpuclk->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: could not register cpuclk %s\n",
> __func__,	name);
> +		ret = PTR_ERR(clk);
> +		goto free_cpuclk_data;
> +	}
> +
> +	samsung_clk_add_lookup(clk, lookup_id);
> +	return 0;
> +
> +free_cpuclk_data:
> +	kfree(cpuclk->data);
> +free_cpuclk:
> +	kfree(cpuclk);
> +	return ret;
> +}
> +
> +static inline void _exynos4210_set_armclk_div(void __iomem *base,
> +			unsigned long div)
> +{
> +	writel((readl(base + DIV_CPU0) & ~0xf) | div, base +
> DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +}
> +
> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
> +				unsigned long parent_rate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +
> +	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> +				EXYNOS4210_ARM_DIV2(base);
> +}
> +
> +/*
> + * This clock notifier is called when the frequency of the parent
> clock
> + * of armclk is to be changed. This notifier handles the setting up
> all
> + * the divider clocks, remux to temporary parent and handling the
> safe
> + * frequency levels when using temporary parent.
> + */
> +static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
> +				unsigned long event, void *data)
> +{
> +	struct clk_notifier_data *ndata = data;
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
> +	struct exynos4210_armclk_data *armclk_data;
> +	unsigned long alt_prate, alt_div, div0, div1, mux_reg;
> +	void __iomem *base;
> +	bool need_safe_freq;
> +
> +	armclk_data = armclk->data;
> +	base = armclk->ctrl_base + armclk->offset;
> +	alt_prate = clk_get_rate(armclk->alt_parent);
> +
> +	if (event == POST_RATE_CHANGE)
> +		goto e4210_armclk_post_rate_change;
> +
> +	/* pre-rate change. find out the divider values to use for
> clock data */
> +	while (armclk_data->prate != ndata->new_rate) {
> +		if (armclk_data->prate == 0)
> +			return NOTIFY_BAD;
> +		armclk_data++;
> +	}
> +
> +	div0 = armclk_data->div0;
> +	div1 = armclk_data->div1;
> +	if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
> +		div1 = readl(base + DIV_CPU1) &
> EXYNOS4210_DIV1_HPM_MASK;
> +		div1 |= ((armclk_data->div1) &
> ~EXYNOS4210_DIV1_HPM_MASK);
> +	}
> +
> +	/*
> +	 * if the new and old parent clock speed is less than the
> clock speed
> +	 * of the alternate parent, then it should be ensured that
> at no point
> +	 * the armclk speed is more than the old_prate until the
> dividers are
> +	 * set.
> +	 */
> +	need_safe_freq = ndata->old_rate < alt_prate &&
> +				ndata->new_rate < alt_prate;
> +	if (need_safe_freq) {
> +		alt_div = _calc_div(alt_prate, ndata->old_rate);
> +		_exynos4210_set_armclk_div(base, alt_div);
> +		div0 |= alt_div;
> +	}
> +
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg | (1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +		;
> +
> +	writel(div0, base + DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +	writel(div1, base + DIV_CPU1);
> +	while (readl(base + DIV_STAT_CPU1) != 0)
> +		;
> +	return NOTIFY_OK;
> +
> +e4210_armclk_post_rate_change:
> +	/* post-rate change event, re-mux back to primary parent */
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> +			;
> +
> +	return NOTIFY_OK;
> +}
> +
> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned
> long drate,
> +					unsigned long prate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +	unsigned long div;
> +
> +	div = drate < prate ? _calc_div(prate, drate) : 0;
> +	_exynos4210_set_armclk_div(base, div);
> +	return 0;
> +}
> +
> +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,
> +};
> +
> +/*
> + * parse divider configuration data from dt for all the cpu clock
> domain
> + * clocks in exynos4210 and compatible SoC's.
> + */
> +static int __init exynos4210_armclk_parser(struct device_node *np,
> void **data) +{
> +	struct exynos4210_armclk_data *tdata;
> +	unsigned long cfg[10], row, col;
> +	const struct property *prop;
> +	const __be32 *val;
> +	u32 cells;
> +	int ret;
> +
> +	if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
> +		return -EINVAL;
> +	prop = of_find_property(np, "samsung,armclk-divider-table",
> NULL);
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -EINVAL;
> +	if ((prop->length / sizeof(u32)) % cells)
> +		return -EINVAL;
> +	row = ((prop->length / sizeof(u32)) / cells) + 1;
> +
> +	*data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
> +	if (!*data)
> +		ret = -ENOMEM;
> +	tdata = *data;
> +
> +	val = prop->value;
> +	for (; row > 1; row--, tdata++) {
> +		for (col = 0; col < cells; col++)
> +			cfg[col] = be32_to_cpup(val++);
> +
> +		tdata->prate = cfg[0] * 1000;
> +		tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5],
> cfg[4],
> +						cfg[3], cfg[2],
> cfg[1]);
> +		tdata->div1 = cells == 10 ?
> +				EXYNOS4210_DIV_CPU1(cfg[9], cfg[8],
> cfg[7]) :
> +				EXYNOS4210_DIV_CPU1(0, cfg[8],
> cfg[7]);
> +	}
> +	tdata->prate = 0;
> +	return 0;
> +}
> +
> +static const struct samsung_cpuclk_soc_data
> exynos4210_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x14200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct samsung_cpuclk_soc_data
> exynos5250_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct of_device_id samsung_clock_ids_armclk[] = {
> +	{ .compatible = "samsung,exynos4210-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos4412-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos5250-clock",
> +			.data = &exynos5250_cpuclk_soc_data, },
> +	{ },
> +};
> +
> +/**
> + * samsung_register_arm_clock: register arm clock with ccf.
> + * @lookup_id: armclk clock output id for the clock controller.
> + * @parent: name of the parent clock for armclk.
> + * @base: base address of the clock controller from which armclk is
> generated.
> + * @np: device tree node pointer of the clock controller (optional).
> + * @ops: clock ops for this clock (optional)
> + */
> +int __init samsung_register_arm_clock(unsigned int lookup_id,
> +		const char **parent_names, unsigned int num_parents,
> +		void __iomem *base, struct device_node *np, struct
> clk_ops *ops) +{
> +	const struct of_device_id *match;
> +	const struct samsung_cpuclk_soc_data *data = NULL;
> +
> +	if (np) {
> +		match = of_match_node(samsung_clock_ids_armclk, np);
> +		data = match ? match->data : NULL;
> +	}
> +
> +	return samsung_cpuclk_register(lookup_id, "armclk",
> parent_names,
> +			num_parents, base, data, np, ops);
> +}
> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
> index 31b4174..5459856 100644
> --- a/drivers/clk/samsung/clk.h
> +++ b/drivers/clk/samsung/clk.h
> @@ -340,4 +340,9 @@ extern void __init
> samsung_clk_register_pll(struct samsung_pll_clock *pll_list, 
>  extern unsigned long _get_rate(const char *clk_name);
>  
> +int __init samsung_register_arm_clock(unsigned int lookup_id,
> +		const char **parent_names, unsigned int num_parents,
> +		void __iomem *base, struct device_node *np,
> +		struct clk_ops *ops);
> +
>  #endif /* __SAMSUNG_CLK_H */

Rest of the code seems OK.

-- 
Best regards,

Lukasz Majewski

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

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

* [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
@ 2014-02-10  9:00     ` Lukasz Majewski
  0 siblings, 0 replies; 43+ messages in thread
From: Lukasz Majewski @ 2014-02-10  9:00 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 configuration data for this clock is obtained from device tree.

I'm a bit confused with the sentence:

> This implementation is reusable for Exynos4x12 and Exynos5250 SoCs as
> well.

It seems that the implementation for Exynos4210 is already reused in
this code for Exynos4412. 

Is the name convention of exynos4210_* after the first SoC supporting
such setup? If yes, I think that it could be explicitly written in the
commit message.

Additionally, the above commit message could also emphasis, that the
implementation for other Exynos4 SoCs (like Exynos4412) is already
in place.


> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  drivers/clk/samsung/Makefile  |    2 +-
>  drivers/clk/samsung/clk-cpu.c |  409
> +++++++++++++++++++++++++++++++++++++++++
> drivers/clk/samsung/clk.h     |    5 + 3 files changed, 415
> insertions(+), 1 deletion(-) 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..673f620
> --- /dev/null
> +++ b/drivers/clk/samsung/clk-cpu.c
> @@ -0,0 +1,409 @@
> +/*
> + * 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
> +
> +#define MAX_DIV			8
> +
> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) +
> 1) +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >>
> 28) & 0xf) + 1) +
> +#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1,
> d0)			\
> +		((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12)
> |	\
> +		 (d1 << 8) | (d0 <<  4))
> +#define EXYNOS4210_DIV_CPU1(d2, d1,
> d0)					\
> +		((d2 << 8) | (d1 << 4) | (d0 << 0))
> +
> +#define EXYNOS4210_DIV1_HPM_MASK	((0x7 << 0) | (0x7 << 4))
> +#define EXYNOS4210_MUX_HPM_MASK		(1 << 20)
> +
> +/**
> + * struct exynos4210_armclk_data: config data to setup exynos4210
> cpu clocks.
> + * @prate:	frequency of the parent clock.
> + * @div0:	value to be programmed in the div_cpu0 register.
> + * @div1:	value to be programmed in the div_cpu1 register.
> + *
> + * This structure holds the divider configuration data for divider
> clocks
> + * belonging to the CMU_CPU clock domain. The parent frequency at
> which these
> + * divider values are vaild is specified in @prate.
> + */
> +struct exynos4210_armclk_data {
> +	unsigned long	prate;
> +	unsigned int	div0;
> +	unsigned int	div1;
> +};
> +
> +/**
> + * struct samsung_cpuclk: information about clock supplied to a CPU
> core.
> + * @hw:		handle between ccf and cpu clock.
> + * @alt_parent:	alternate parent clock to use when switching
> the speed
> + *		of the primary parent 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.
> + * @clk_nb:	clock notifier registered for changes in clock
> speed of the
> + *		primary parent clock.
> + * @data:	optional data which the acutal instantiation of
> this clock
> + *		can use.
> + */
> +struct samsung_cpuclk {
> +	struct clk_hw		hw;
> +	struct clk		*alt_parent;
> +	void __iomem		*ctrl_base;
> +	unsigned long		offset;
> +	struct notifier_block	clk_nb;
> +	void			*data;
> +};
> +
> +#define to_samsung_cpuclk_hw(hw) container_of(hw, struct
> samsung_cpuclk, hw) +#define to_samsung_cpuclk_nb(nb)
> container_of(nb, struct samsung_cpuclk, clk_nb) +
> +/**
> + * struct samsung_cpuclk_soc_data: soc specific data for cpu clocks.
> + * @parser:	pointer to a function that can parse SoC specific
> data.
> + * @ops:	clock operations to be used for this clock.
> + * @offset:	optional offset from base of clock controller
> register base, to
> + *		be used when accessing clock controller registers
> related to the
> + *		cpu clock.
> + * @clk_cb:	the clock notifier callback to be called for
> changes in the
> + *		clock rate of the primary parent clock.
> + *
> + * This structure provides SoC specific data for ARM clocks. Based on
> + * the compatible value of the clock controller node, the value of
> the
> + * fields in this structure can be populated.
> + */
> +struct samsung_cpuclk_soc_data {
> +	int (*parser)(struct device_node *, void **);
> +	const struct clk_ops *ops;
> +	unsigned int offset;
> +	int (*clk_cb)(struct notifier_block *nb, unsigned long evt,
> void *data); +};
> +
> +/* common round rate callback useable for all types of cpu clocks */
> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	struct clk *parent = __clk_get_parent(hw->clk);
> +	unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
> +	unsigned long t_prate, best_div = 1;
> +	unsigned long delta, min_delta = UINT_MAX;
> +
> +	do {
> +		t_prate = __clk_round_rate(parent, drate * best_div);
> +		delta = drate - (t_prate / best_div);
> +		if (delta < min_delta) {
> +			*prate = t_prate;
> +			min_delta = delta;
> +		}
> +		if (!delta)
> +			break;
> +		best_div++;
> +	} while ((drate * best_div) < max_prate && best_div <=
> MAX_DIV); +
> +	return t_prate / best_div;
> +}
> +
> +static unsigned long _calc_div(unsigned long prate, unsigned long
> drate) +{
> +	unsigned long div = prate / drate;
> +
> +	WARN_ON(div >= MAX_DIV);
> +	return (!(prate % drate)) ? div-- : div;
> +}
> +
> +/* helper function to register a cpu clock */
> +static int __init samsung_cpuclk_register(unsigned int lookup_id,
> +		const char *name, const char **parents,
> +		unsigned int num_parents, void __iomem *base,
> +		const struct samsung_cpuclk_soc_data *soc_data,
> +		struct device_node *np, const struct clk_ops *ops)
> +{
> +	struct samsung_cpuclk *cpuclk;
> +	struct clk_init_data init;
> +	struct clk *clk;
> +	int ret;
> +
> +	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> +	if (!cpuclk) {
> +		pr_err("%s: could not allocate memory for %s
> clock\n",
> +					__func__, name);
> +		return -ENOMEM;
> +	}
> +
> +	init.name = name;
> +	init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
> +	init.parent_names = parents;
> +	init.num_parents = 1;
> +	init.ops = ops;
> +
> +	cpuclk->hw.init = &init;
> +	cpuclk->ctrl_base = base;
> +
> +	if (soc_data && soc_data->parser) {
> +		ret = soc_data->parser(np, &cpuclk->data);
> +		if (ret) {
> +			pr_err("%s: error %d in parsing %s clock
> data",
> +					__func__, ret, name);
> +			ret = -EINVAL;
> +			goto free_cpuclk;
> +		}
> +		cpuclk->offset = soc_data->offset;
> +		init.ops = soc_data->ops;
> +	}
> +
> +	if (soc_data && soc_data->clk_cb) {
> +		cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
> +		if (clk_notifier_register(__clk_lookup(parents[0]),
> +				&cpuclk->clk_nb)) {
> +			pr_err("%s: failed to register clock
> notifier for %s\n",
> +					__func__, name);
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	if (num_parents == 2) {
> +		cpuclk->alt_parent = __clk_lookup(parents[1]);
> +		if (!cpuclk->alt_parent) {
> +			pr_err("%s: could not lookup alternate
> parent %s\n",
> +					__func__, parents[1]);
> +			ret = -EINVAL;
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	clk = clk_register(NULL, &cpuclk->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: could not register cpuclk %s\n",
> __func__,	name);
> +		ret = PTR_ERR(clk);
> +		goto free_cpuclk_data;
> +	}
> +
> +	samsung_clk_add_lookup(clk, lookup_id);
> +	return 0;
> +
> +free_cpuclk_data:
> +	kfree(cpuclk->data);
> +free_cpuclk:
> +	kfree(cpuclk);
> +	return ret;
> +}
> +
> +static inline void _exynos4210_set_armclk_div(void __iomem *base,
> +			unsigned long div)
> +{
> +	writel((readl(base + DIV_CPU0) & ~0xf) | div, base +
> DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +}
> +
> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
> +				unsigned long parent_rate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +
> +	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> +				EXYNOS4210_ARM_DIV2(base);
> +}
> +
> +/*
> + * This clock notifier is called when the frequency of the parent
> clock
> + * of armclk is to be changed. This notifier handles the setting up
> all
> + * the divider clocks, remux to temporary parent and handling the
> safe
> + * frequency levels when using temporary parent.
> + */
> +static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
> +				unsigned long event, void *data)
> +{
> +	struct clk_notifier_data *ndata = data;
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
> +	struct exynos4210_armclk_data *armclk_data;
> +	unsigned long alt_prate, alt_div, div0, div1, mux_reg;
> +	void __iomem *base;
> +	bool need_safe_freq;
> +
> +	armclk_data = armclk->data;
> +	base = armclk->ctrl_base + armclk->offset;
> +	alt_prate = clk_get_rate(armclk->alt_parent);
> +
> +	if (event == POST_RATE_CHANGE)
> +		goto e4210_armclk_post_rate_change;
> +
> +	/* pre-rate change. find out the divider values to use for
> clock data */
> +	while (armclk_data->prate != ndata->new_rate) {
> +		if (armclk_data->prate == 0)
> +			return NOTIFY_BAD;
> +		armclk_data++;
> +	}
> +
> +	div0 = armclk_data->div0;
> +	div1 = armclk_data->div1;
> +	if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
> +		div1 = readl(base + DIV_CPU1) &
> EXYNOS4210_DIV1_HPM_MASK;
> +		div1 |= ((armclk_data->div1) &
> ~EXYNOS4210_DIV1_HPM_MASK);
> +	}
> +
> +	/*
> +	 * if the new and old parent clock speed is less than the
> clock speed
> +	 * of the alternate parent, then it should be ensured that
> at no point
> +	 * the armclk speed is more than the old_prate until the
> dividers are
> +	 * set.
> +	 */
> +	need_safe_freq = ndata->old_rate < alt_prate &&
> +				ndata->new_rate < alt_prate;
> +	if (need_safe_freq) {
> +		alt_div = _calc_div(alt_prate, ndata->old_rate);
> +		_exynos4210_set_armclk_div(base, alt_div);
> +		div0 |= alt_div;
> +	}
> +
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg | (1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +		;
> +
> +	writel(div0, base + DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +	writel(div1, base + DIV_CPU1);
> +	while (readl(base + DIV_STAT_CPU1) != 0)
> +		;
> +	return NOTIFY_OK;
> +
> +e4210_armclk_post_rate_change:
> +	/* post-rate change event, re-mux back to primary parent */
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> +			;
> +
> +	return NOTIFY_OK;
> +}
> +
> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned
> long drate,
> +					unsigned long prate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +	unsigned long div;
> +
> +	div = drate < prate ? _calc_div(prate, drate) : 0;
> +	_exynos4210_set_armclk_div(base, div);
> +	return 0;
> +}
> +
> +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,
> +};
> +
> +/*
> + * parse divider configuration data from dt for all the cpu clock
> domain
> + * clocks in exynos4210 and compatible SoC's.
> + */
> +static int __init exynos4210_armclk_parser(struct device_node *np,
> void **data) +{
> +	struct exynos4210_armclk_data *tdata;
> +	unsigned long cfg[10], row, col;
> +	const struct property *prop;
> +	const __be32 *val;
> +	u32 cells;
> +	int ret;
> +
> +	if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
> +		return -EINVAL;
> +	prop = of_find_property(np, "samsung,armclk-divider-table",
> NULL);
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -EINVAL;
> +	if ((prop->length / sizeof(u32)) % cells)
> +		return -EINVAL;
> +	row = ((prop->length / sizeof(u32)) / cells) + 1;
> +
> +	*data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
> +	if (!*data)
> +		ret = -ENOMEM;
> +	tdata = *data;
> +
> +	val = prop->value;
> +	for (; row > 1; row--, tdata++) {
> +		for (col = 0; col < cells; col++)
> +			cfg[col] = be32_to_cpup(val++);
> +
> +		tdata->prate = cfg[0] * 1000;
> +		tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5],
> cfg[4],
> +						cfg[3], cfg[2],
> cfg[1]);
> +		tdata->div1 = cells == 10 ?
> +				EXYNOS4210_DIV_CPU1(cfg[9], cfg[8],
> cfg[7]) :
> +				EXYNOS4210_DIV_CPU1(0, cfg[8],
> cfg[7]);
> +	}
> +	tdata->prate = 0;
> +	return 0;
> +}
> +
> +static const struct samsung_cpuclk_soc_data
> exynos4210_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x14200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct samsung_cpuclk_soc_data
> exynos5250_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct of_device_id samsung_clock_ids_armclk[] = {
> +	{ .compatible = "samsung,exynos4210-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos4412-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos5250-clock",
> +			.data = &exynos5250_cpuclk_soc_data, },
> +	{ },
> +};
> +
> +/**
> + * samsung_register_arm_clock: register arm clock with ccf.
> + * @lookup_id: armclk clock output id for the clock controller.
> + * @parent: name of the parent clock for armclk.
> + * @base: base address of the clock controller from which armclk is
> generated.
> + * @np: device tree node pointer of the clock controller (optional).
> + * @ops: clock ops for this clock (optional)
> + */
> +int __init samsung_register_arm_clock(unsigned int lookup_id,
> +		const char **parent_names, unsigned int num_parents,
> +		void __iomem *base, struct device_node *np, struct
> clk_ops *ops) +{
> +	const struct of_device_id *match;
> +	const struct samsung_cpuclk_soc_data *data = NULL;
> +
> +	if (np) {
> +		match = of_match_node(samsung_clock_ids_armclk, np);
> +		data = match ? match->data : NULL;
> +	}
> +
> +	return samsung_cpuclk_register(lookup_id, "armclk",
> parent_names,
> +			num_parents, base, data, np, ops);
> +}
> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
> index 31b4174..5459856 100644
> --- a/drivers/clk/samsung/clk.h
> +++ b/drivers/clk/samsung/clk.h
> @@ -340,4 +340,9 @@ extern void __init
> samsung_clk_register_pll(struct samsung_pll_clock *pll_list, 
>  extern unsigned long _get_rate(const char *clk_name);
>  
> +int __init samsung_register_arm_clock(unsigned int lookup_id,
> +		const char **parent_names, unsigned int num_parents,
> +		void __iomem *base, struct device_node *np,
> +		struct clk_ops *ops);
> +
>  #endif /* __SAMSUNG_CLK_H */

Rest of the code seems OK.

-- 
Best regards,

Lukasz Majewski

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

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-07 15:55   ` Thomas Abraham
@ 2014-02-12 14:58     ` Tomasz Figa
  -1 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-12 14:58 UTC (permalink / raw)
  To: Thomas Abraham, cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, l.majewski,
	viresh.kumar, thomas.ab, heiko, Rafael J. Wysocki

Hi Thomas,

On 07.02.2014 16:55, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
>
> Lookup for the optional boost-frequency property in cpu0 node and if
> available, enable support for boost mode frequencies. The frequencies
> usable in boost mode are determined while preparing the cpufreq table
> from the list of operating points available.
>
> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
> this driver by default. On platforms that do not support boost mode,
> the boost mode frequencies will not be specified in cpu0 node and
> hence the boost mode support will not be enabled. Since this driver
> anyways depends on THERMAL config option, it is safe to enable
> CPU_FREQ_BOOST_SW config option as default.
>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>   Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>   drivers/cpufreq/Kconfig                                    |    1 +
>   drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>   3 files changed, 6 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> index f055515..60f321a 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> @@ -19,6 +19,8 @@ Optional properties:
>   - cooling-min-level:
>   - cooling-max-level:
>        Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
> +- boost-frequency:
> +     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>
>   Examples:
>
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 4b029c0..52cc704 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>   	tristate "Generic CPU0 cpufreq driver"
>   	depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>   	select PM_OPP
> +	select CPU_FREQ_BOOST_SW
>   	help
>   	  This adds a generic cpufreq driver for CPU0 frequency management.
>   	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index 0c12ffc..06539eb 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>   			transition_latency += ret * 1000;
>   	}
>
> +	if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
> +		cpu0_cpufreq_driver.boost_supported = true;
> +
>   	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>   	if (ret) {
>   		pr_err("failed register driver: %d\n", ret);
>

I'd say that boost should be enabled depending on user's preference, as 
done before in Exynos cpufreq driver. So both presence of 
boost-frequency property and state of CPU_FREQ_BOOST_SW should be 
considered.

As for CPU_FREQ_BOOST_SW, I don't think it should be always selected, 
but ather, either converted to a user-selectable bool entry or made 
selectable by other entry, like current ARM_EXYNOS_CPU_FREQ_BOOST_SW.

Best regards,
Tomasz

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-12 14:58     ` Tomasz Figa
  0 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-12 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On 07.02.2014 16:55, Thomas Abraham wrote:
> From: Thomas Abraham <thomas.ab@samsung.com>
>
> Lookup for the optional boost-frequency property in cpu0 node and if
> available, enable support for boost mode frequencies. The frequencies
> usable in boost mode are determined while preparing the cpufreq table
> from the list of operating points available.
>
> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
> this driver by default. On platforms that do not support boost mode,
> the boost mode frequencies will not be specified in cpu0 node and
> hence the boost mode support will not be enabled. Since this driver
> anyways depends on THERMAL config option, it is safe to enable
> CPU_FREQ_BOOST_SW config option as default.
>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>   Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>   drivers/cpufreq/Kconfig                                    |    1 +
>   drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>   3 files changed, 6 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> index f055515..60f321a 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> @@ -19,6 +19,8 @@ Optional properties:
>   - cooling-min-level:
>   - cooling-max-level:
>        Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
> +- boost-frequency:
> +     Please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>
>   Examples:
>
> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
> index 4b029c0..52cc704 100644
> --- a/drivers/cpufreq/Kconfig
> +++ b/drivers/cpufreq/Kconfig
> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>   	tristate "Generic CPU0 cpufreq driver"
>   	depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>   	select PM_OPP
> +	select CPU_FREQ_BOOST_SW
>   	help
>   	  This adds a generic cpufreq driver for CPU0 frequency management.
>   	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
> diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
> index 0c12ffc..06539eb 100644
> --- a/drivers/cpufreq/cpufreq-cpu0.c
> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
>   			transition_latency += ret * 1000;
>   	}
>
> +	if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
> +		cpu0_cpufreq_driver.boost_supported = true;
> +
>   	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>   	if (ret) {
>   		pr_err("failed register driver: %d\n", ret);
>

I'd say that boost should be enabled depending on user's preference, as 
done before in Exynos cpufreq driver. So both presence of 
boost-frequency property and state of CPU_FREQ_BOOST_SW should be 
considered.

As for CPU_FREQ_BOOST_SW, I don't think it should be always selected, 
but ather, either converted to a user-selectable bool entry or made 
selectable by other entry, like current ARM_EXYNOS_CPU_FREQ_BOOST_SW.

Best regards,
Tomasz

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

* Re: [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-02-07 15:55   ` Thomas Abraham
@ 2014-02-12 18:25     ` Tomasz Figa
  -1 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-12 18:25 UTC (permalink / raw)
  To: Thomas Abraham, cpufreq, linux-arm-kernel
  Cc: linux-samsung-soc, mturquette, shawn.guo, kgene.kim, l.majewski,
	viresh.kumar, thomas.ab, heiko

Hi Thomas,

On 07.02.2014 16:55, Thomas Abraham wrote:
> 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
> configuration data for this clock is obtained from device tree. This
> implementation is reusable for Exynos4x12 and Exynos5250 SoCs as well.
>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>   drivers/clk/samsung/Makefile  |    2 +-
>   drivers/clk/samsung/clk-cpu.c |  409 +++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/samsung/clk.h     |    5 +
>   3 files changed, 415 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/clk/samsung/clk-cpu.c

[snip]

> diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
> new file mode 100644
> index 0000000..673f620
> --- /dev/null
> +++ b/drivers/clk/samsung/clk-cpu.c
> @@ -0,0 +1,409 @@

[snip]

> +#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
> +
> +#define MAX_DIV			8
> +
> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
> +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf) + 1)

Those are 3-bit dividers, so the mask should be rather 0x7, shouldn't it?

Btw. Somehow I feel like this kind of macros is simply obfuscating code 
without any real benefits. Could you rewrite them to simply take the 
value of DIV_CPU0 register, without hiding readl behind the scenes?

> +
> +#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1, d0)			\
> +		((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12) |	\
> +		 (d1 << 8) | (d0 <<  4))
> +#define EXYNOS4210_DIV_CPU1(d2, d1, d0)					\
> +		((d2 << 8) | (d1 << 4) | (d0 << 0))
> +
> +#define EXYNOS4210_DIV1_HPM_MASK	((0x7 << 0) | (0x7 << 4))
> +#define EXYNOS4210_MUX_HPM_MASK		(1 << 20)

[snip]

> +/* common round rate callback useable for all types of cpu clocks */
> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	struct clk *parent = __clk_get_parent(hw->clk);
> +	unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
> +	unsigned long t_prate, best_div = 1;
> +	unsigned long delta, min_delta = UINT_MAX;
> +
> +	do {
> +		t_prate = __clk_round_rate(parent, drate * best_div);
> +		delta = drate - (t_prate / best_div);
> +		if (delta < min_delta) {
> +			*prate = t_prate;
> +			min_delta = delta;
> +		}
> +		if (!delta)
> +			break;
> +		best_div++;
> +	} while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
> +
> +	return t_prate / best_div;
> +}

I think there is something wrong with the code above. You increment 
best_div in every iteration of the loop and use it to calculate the 
final best frequency. Shouldn't best_div be the divisor which was found 
to give the least delta and so the loop should rather iterate on a 
different variable and store best_div only if (delta < min_delta) 
condition is true?

Anyway, I wonder if you couldn't somehow reuse the code from 
drivers/clk/clk-divider.c...

> +
> +static unsigned long _calc_div(unsigned long prate, unsigned long drate)
> +{
> +	unsigned long div = prate / drate;
> +
> +	WARN_ON(div >= MAX_DIV);
> +	return (!(prate % drate)) ? div-- : div;
> +}
> +
> +/* helper function to register a cpu clock */
> +static int __init samsung_cpuclk_register(unsigned int lookup_id,

Isn't the name a bit too generic? I'd say it should be 
exynos_cpuclk_register(), since the implementation is rather Exynos 
specific anyway.

> +		const char *name, const char **parents,
> +		unsigned int num_parents, void __iomem *base,
> +		const struct samsung_cpuclk_soc_data *soc_data,
> +		struct device_node *np, const struct clk_ops *ops)
> +{
> +	struct samsung_cpuclk *cpuclk;
> +	struct clk_init_data init;
> +	struct clk *clk;
> +	int ret;
> +
> +	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> +	if (!cpuclk) {
> +		pr_err("%s: could not allocate memory for %s clock\n",
> +					__func__, name);
> +		return -ENOMEM;
> +	}
> +
> +	init.name = name;
> +	init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;

Why CLK_GET_RATE_NOCACHE? There is only one entity that can change rate 
of this clock and it is this clock driver, so it can update the cache on 
any change.

> +	init.parent_names = parents;
> +	init.num_parents = 1;

I believe this clock should take two clocks as its parents, because it 
can dynamically switch between mout_apll and mout_mpll using mout_core mux.

> +	init.ops = ops;
> +
> +	cpuclk->hw.init = &init;
> +	cpuclk->ctrl_base = base;
> +
> +	if (soc_data && soc_data->parser) {

Is it even possible to instantiate this clock without soc_data and 
parser function? Shouldn't it simply bail out instead?

> +		ret = soc_data->parser(np, &cpuclk->data);
> +		if (ret) {
> +			pr_err("%s: error %d in parsing %s clock data",
> +					__func__, ret, name);
> +			ret = -EINVAL;
> +			goto free_cpuclk;
> +		}
> +		cpuclk->offset = soc_data->offset;
> +		init.ops = soc_data->ops;
> +	}
> +
> +	if (soc_data && soc_data->clk_cb) {

Same here. Does it make any sense to instantiate this clock without a 
notifier callback?

> +		cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
> +		if (clk_notifier_register(__clk_lookup(parents[0]),
> +				&cpuclk->clk_nb)) {
> +			pr_err("%s: failed to register clock notifier for %s\n",
> +					__func__, name);
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	if (num_parents == 2) {

When num_parents could be other than 2?

> +		cpuclk->alt_parent = __clk_lookup(parents[1]);
> +		if (!cpuclk->alt_parent) {
> +			pr_err("%s: could not lookup alternate parent %s\n",
> +					__func__, parents[1]);
> +			ret = -EINVAL;
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	clk = clk_register(NULL, &cpuclk->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
> +		ret = PTR_ERR(clk);
> +		goto free_cpuclk_data;
> +	}
> +
> +	samsung_clk_add_lookup(clk, lookup_id);
> +	return 0;
> +
> +free_cpuclk_data:
> +	kfree(cpuclk->data);
> +free_cpuclk:
> +	kfree(cpuclk);
> +	return ret;
> +}
> +
> +static inline void _exynos4210_set_armclk_div(void __iomem *base,
> +			unsigned long div)

I'd say it would be better to leave the decision about inlining to the 
compiler.

> +{
> +	writel((readl(base + DIV_CPU0) & ~0xf) | div, base + DIV_CPU0);

CORE_RATIO bitfield is 3-bit wide.

> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;

Wouldn't it be better to add some timeout and print an error to make 
sure that even if something wrong happens the user will know that it 
happened?

> +}
> +
> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
> +				unsigned long parent_rate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +
> +	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> +				EXYNOS4210_ARM_DIV2(base);

The code would be more readable if you read the register to a temporary 
variable using readl() directly and then accessing its contents.

> +}
> +
> +/*
> + * This clock notifier is called when the frequency of the parent clock
> + * of armclk is to be changed. This notifier handles the setting up all
> + * the divider clocks, remux to temporary parent and handling the safe
> + * frequency levels when using temporary parent.
> + */
> +static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
> +				unsigned long event, void *data)
> +{
> +	struct clk_notifier_data *ndata = data;
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
> +	struct exynos4210_armclk_data *armclk_data;
> +	unsigned long alt_prate, alt_div, div0, div1, mux_reg;
> +	void __iomem *base;
> +	bool need_safe_freq;
> +
> +	armclk_data = armclk->data;
> +	base = armclk->ctrl_base + armclk->offset;
> +	alt_prate = clk_get_rate(armclk->alt_parent);
> +
> +	if (event == POST_RATE_CHANGE)
> +		goto e4210_armclk_post_rate_change;

This would look better if you separated the main configuration code from 
the notifier callback, like this:

	int ret = 0;

	switch (event) {
	case POST_RATE_CHANGE:
		ret = exynos4210_armclk_post_rate_change(...);
		break;
	case PRE_RATE_CHANGE:
		ret = exynos4210_armclk_pre_rate_change(...);
		break;
	}

	return notifier_from_errno(ret);

By the way, I wonder if some of this couldn't simply happen in 
.set_rate() op of this clock, since

> +
> +	/* pre-rate change. find out the divider values to use for clock data */
> +	while (armclk_data->prate != ndata->new_rate) {
> +		if (armclk_data->prate == 0)
> +			return NOTIFY_BAD;
> +		armclk_data++;
> +	}
> +
> +	div0 = armclk_data->div0;
> +	div1 = armclk_data->div1;

You should always use read-modify-write for such registers to preserve 
reserved bits. This will also clean a bit safe frequency activation, see 
below.

> +	if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
> +		div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
> +		div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
> +	}
> +
> +	/*
> +	 * if the new and old parent clock speed is less than the clock speed
> +	 * of the alternate parent, then it should be ensured that at no point
> +	 * the armclk speed is more than the old_prate until the dividers are
> +	 * set.
> +	 */
> +	need_safe_freq = ndata->old_rate < alt_prate &&
> +				ndata->new_rate < alt_prate;

Are you sure this condition is correct? The parent clock (PLL) alone 
doesn't fully determine the rate of ARM clock, because you are also 
changing div_core. So you can end up with PLL going down, while ARM 
clock going up, because the divisors are significantly lowered.

I think you should compare ARM clock rates here OR just remove div_core 
configuration, keeping it as 0 (divide by 1) all the time, except when 
safe frequency is active.

> +	if (need_safe_freq) {
> +		alt_div = _calc_div(alt_prate, ndata->old_rate);
> +		_exynos4210_set_armclk_div(base, alt_div);
> +		div0 |= alt_div;
> +	}


You could move div0 and div1 calculation (including reading original 
values of registers) here to remove "div0 |= alt_div;" line from the if 
above and fully isolate ARM divisor setup code from changing other divisors.

> +
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg | (1 << 16), base + SRC_CPU);

Don't you need to hold the samsung clock spinlock when writing to this 
register? It seems to control more muxes than just this one.

> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +		;
> +
> +	writel(div0, base + DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +	writel(div1, base + DIV_CPU1);
> +	while (readl(base + DIV_STAT_CPU1) != 0)
> +		;

You seem to always perform the configuration in pre rate change 
notifier, but original cpufreq code used to do it depending on whether 
the new frequency is less than old or not, e.g.

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);
         }
}

set_clkdiv does the following:
   1) set DIV_CPU0
   2) wait for DIV_STAT_CPU0
   3) set DIV_CPU1
   4) wait for DIV_STAT_CPU1

and set_apll:
   1) set parent to MPLL
   2) wait for MUX_STAT_CPU
   3) set APLL rate
   4) set parent to APLL
   5) wait for MUX_STAT_CPU

Note that higher index means lower frequency.

Btw. It would be nice to handle timeouts here as well, to prevent system 
lockups.

> +	return NOTIFY_OK;
> +
> +e4210_armclk_post_rate_change:
> +	/* post-rate change event, re-mux back to primary parent */
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> +			;

nit: Too many tabs.

Timeout would be nice too.

> +
> +	return NOTIFY_OK;
> +}
> +
> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long drate,
> +					unsigned long prate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +	unsigned long div;
> +
> +	div = drate < prate ? _calc_div(prate, drate) : 0;
> +	_exynos4210_set_armclk_div(base, div);
> +	return 0;

Hmm, here you are supposed to set exactly the rate given to you in drate 
argument. Core clock code calls your .round_rate() first and the rate 
returned by it is what .set_rate() gets as drate. You can safely assume 
that

> +}
> +
> +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,
> +};
> +
> +/*
> + * parse divider configuration data from dt for all the cpu clock domain
> + * clocks in exynos4210 and compatible SoC's.
> + */
> +static int __init exynos4210_armclk_parser(struct device_node *np, void **data)
> +{
> +	struct exynos4210_armclk_data *tdata;
> +	unsigned long cfg[10], row, col;
> +	const struct property *prop;
> +	const __be32 *val;
> +	u32 cells;
> +	int ret;
> +
> +	if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
> +		return -EINVAL;

The property should be prefixed with "#" as other properties defining 
number of cells.

Also you should check if cells value is correct, e.g. a number of cells 
supported

> +	prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -EINVAL;
> +	if ((prop->length / sizeof(u32)) % cells)
> +		return -EINVAL;
> +	row = ((prop->length / sizeof(u32)) / cells) + 1;

Why + 1? Also the variable could be named in a bit more meaningful way, 
e.g. num_rows.

> +
> +	*data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
> +	if (!*data)
> +		ret = -ENOMEM;
> +	tdata = *data;
> +
> +	val = prop->value;
> +	for (; row > 1; row--, tdata++) {
> +		for (col = 0; col < cells; col++)
> +			cfg[col] = be32_to_cpup(val++);

You could use of_prop_next_u32() here.

> +
> +		tdata->prate = cfg[0] * 1000;
> +		tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5], cfg[4],
> +						cfg[3], cfg[2], cfg[1]);
> +		tdata->div1 = cells == 10 ?
> +				EXYNOS4210_DIV_CPU1(cfg[9], cfg[8], cfg[7]) :
> +				EXYNOS4210_DIV_CPU1(0, cfg[8], cfg[7]);
> +	}
> +	tdata->prate = 0;
> +	return 0;
> +}
> +
> +static const struct samsung_cpuclk_soc_data exynos4210_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x14200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct samsung_cpuclk_soc_data exynos5250_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct of_device_id samsung_clock_ids_armclk[] = {
> +	{ .compatible = "samsung,exynos4210-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos4412-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos5250-clock",
> +			.data = &exynos5250_cpuclk_soc_data, },
> +	{ },
> +};
> +
> +/**
> + * samsung_register_arm_clock: register arm clock with ccf.
> + * @lookup_id: armclk clock output id for the clock controller.
> + * @parent: name of the parent clock for armclk.
> + * @base: base address of the clock controller from which armclk is generated.
> + * @np: device tree node pointer of the clock controller (optional).
> + * @ops: clock ops for this clock (optional)
> + */
> +int __init samsung_register_arm_clock(unsigned int lookup_id,
> +		const char **parent_names, unsigned int num_parents,
> +		void __iomem *base, struct device_node *np, struct clk_ops *ops)
> +{
> +	const struct of_device_id *match;
> +	const struct samsung_cpuclk_soc_data *data = NULL;
> +
> +	if (np) {
> +		match = of_match_node(samsung_clock_ids_armclk, np);
> +		data = match ? match->data : NULL;
> +	}

Since this is rather Exynos-specific and Exynos is DT-only, np being 
NULL would be simply an error.

Best regards,
Tomasz

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

* [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
@ 2014-02-12 18:25     ` Tomasz Figa
  0 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-12 18:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thomas,

On 07.02.2014 16:55, Thomas Abraham wrote:
> 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
> configuration data for this clock is obtained from device tree. This
> implementation is reusable for Exynos4x12 and Exynos5250 SoCs as well.
>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>   drivers/clk/samsung/Makefile  |    2 +-
>   drivers/clk/samsung/clk-cpu.c |  409 +++++++++++++++++++++++++++++++++++++++++
>   drivers/clk/samsung/clk.h     |    5 +
>   3 files changed, 415 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/clk/samsung/clk-cpu.c

[snip]

> diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
> new file mode 100644
> index 0000000..673f620
> --- /dev/null
> +++ b/drivers/clk/samsung/clk-cpu.c
> @@ -0,0 +1,409 @@

[snip]

> +#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
> +
> +#define MAX_DIV			8
> +
> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
> +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf) + 1)

Those are 3-bit dividers, so the mask should be rather 0x7, shouldn't it?

Btw. Somehow I feel like this kind of macros is simply obfuscating code 
without any real benefits. Could you rewrite them to simply take the 
value of DIV_CPU0 register, without hiding readl behind the scenes?

> +
> +#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1, d0)			\
> +		((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12) |	\
> +		 (d1 << 8) | (d0 <<  4))
> +#define EXYNOS4210_DIV_CPU1(d2, d1, d0)					\
> +		((d2 << 8) | (d1 << 4) | (d0 << 0))
> +
> +#define EXYNOS4210_DIV1_HPM_MASK	((0x7 << 0) | (0x7 << 4))
> +#define EXYNOS4210_MUX_HPM_MASK		(1 << 20)

[snip]

> +/* common round rate callback useable for all types of cpu clocks */
> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	struct clk *parent = __clk_get_parent(hw->clk);
> +	unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
> +	unsigned long t_prate, best_div = 1;
> +	unsigned long delta, min_delta = UINT_MAX;
> +
> +	do {
> +		t_prate = __clk_round_rate(parent, drate * best_div);
> +		delta = drate - (t_prate / best_div);
> +		if (delta < min_delta) {
> +			*prate = t_prate;
> +			min_delta = delta;
> +		}
> +		if (!delta)
> +			break;
> +		best_div++;
> +	} while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
> +
> +	return t_prate / best_div;
> +}

I think there is something wrong with the code above. You increment 
best_div in every iteration of the loop and use it to calculate the 
final best frequency. Shouldn't best_div be the divisor which was found 
to give the least delta and so the loop should rather iterate on a 
different variable and store best_div only if (delta < min_delta) 
condition is true?

Anyway, I wonder if you couldn't somehow reuse the code from 
drivers/clk/clk-divider.c...

> +
> +static unsigned long _calc_div(unsigned long prate, unsigned long drate)
> +{
> +	unsigned long div = prate / drate;
> +
> +	WARN_ON(div >= MAX_DIV);
> +	return (!(prate % drate)) ? div-- : div;
> +}
> +
> +/* helper function to register a cpu clock */
> +static int __init samsung_cpuclk_register(unsigned int lookup_id,

Isn't the name a bit too generic? I'd say it should be 
exynos_cpuclk_register(), since the implementation is rather Exynos 
specific anyway.

> +		const char *name, const char **parents,
> +		unsigned int num_parents, void __iomem *base,
> +		const struct samsung_cpuclk_soc_data *soc_data,
> +		struct device_node *np, const struct clk_ops *ops)
> +{
> +	struct samsung_cpuclk *cpuclk;
> +	struct clk_init_data init;
> +	struct clk *clk;
> +	int ret;
> +
> +	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
> +	if (!cpuclk) {
> +		pr_err("%s: could not allocate memory for %s clock\n",
> +					__func__, name);
> +		return -ENOMEM;
> +	}
> +
> +	init.name = name;
> +	init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;

Why CLK_GET_RATE_NOCACHE? There is only one entity that can change rate 
of this clock and it is this clock driver, so it can update the cache on 
any change.

> +	init.parent_names = parents;
> +	init.num_parents = 1;

I believe this clock should take two clocks as its parents, because it 
can dynamically switch between mout_apll and mout_mpll using mout_core mux.

> +	init.ops = ops;
> +
> +	cpuclk->hw.init = &init;
> +	cpuclk->ctrl_base = base;
> +
> +	if (soc_data && soc_data->parser) {

Is it even possible to instantiate this clock without soc_data and 
parser function? Shouldn't it simply bail out instead?

> +		ret = soc_data->parser(np, &cpuclk->data);
> +		if (ret) {
> +			pr_err("%s: error %d in parsing %s clock data",
> +					__func__, ret, name);
> +			ret = -EINVAL;
> +			goto free_cpuclk;
> +		}
> +		cpuclk->offset = soc_data->offset;
> +		init.ops = soc_data->ops;
> +	}
> +
> +	if (soc_data && soc_data->clk_cb) {

Same here. Does it make any sense to instantiate this clock without a 
notifier callback?

> +		cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
> +		if (clk_notifier_register(__clk_lookup(parents[0]),
> +				&cpuclk->clk_nb)) {
> +			pr_err("%s: failed to register clock notifier for %s\n",
> +					__func__, name);
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	if (num_parents == 2) {

When num_parents could be other than 2?

> +		cpuclk->alt_parent = __clk_lookup(parents[1]);
> +		if (!cpuclk->alt_parent) {
> +			pr_err("%s: could not lookup alternate parent %s\n",
> +					__func__, parents[1]);
> +			ret = -EINVAL;
> +			goto free_cpuclk_data;
> +		}
> +	}
> +
> +	clk = clk_register(NULL, &cpuclk->hw);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
> +		ret = PTR_ERR(clk);
> +		goto free_cpuclk_data;
> +	}
> +
> +	samsung_clk_add_lookup(clk, lookup_id);
> +	return 0;
> +
> +free_cpuclk_data:
> +	kfree(cpuclk->data);
> +free_cpuclk:
> +	kfree(cpuclk);
> +	return ret;
> +}
> +
> +static inline void _exynos4210_set_armclk_div(void __iomem *base,
> +			unsigned long div)

I'd say it would be better to leave the decision about inlining to the 
compiler.

> +{
> +	writel((readl(base + DIV_CPU0) & ~0xf) | div, base + DIV_CPU0);

CORE_RATIO bitfield is 3-bit wide.

> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;

Wouldn't it be better to add some timeout and print an error to make 
sure that even if something wrong happens the user will know that it 
happened?

> +}
> +
> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
> +				unsigned long parent_rate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +
> +	return parent_rate / EXYNOS4210_ARM_DIV1(base) /
> +				EXYNOS4210_ARM_DIV2(base);

The code would be more readable if you read the register to a temporary 
variable using readl() directly and then accessing its contents.

> +}
> +
> +/*
> + * This clock notifier is called when the frequency of the parent clock
> + * of armclk is to be changed. This notifier handles the setting up all
> + * the divider clocks, remux to temporary parent and handling the safe
> + * frequency levels when using temporary parent.
> + */
> +static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
> +				unsigned long event, void *data)
> +{
> +	struct clk_notifier_data *ndata = data;
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
> +	struct exynos4210_armclk_data *armclk_data;
> +	unsigned long alt_prate, alt_div, div0, div1, mux_reg;
> +	void __iomem *base;
> +	bool need_safe_freq;
> +
> +	armclk_data = armclk->data;
> +	base = armclk->ctrl_base + armclk->offset;
> +	alt_prate = clk_get_rate(armclk->alt_parent);
> +
> +	if (event == POST_RATE_CHANGE)
> +		goto e4210_armclk_post_rate_change;

This would look better if you separated the main configuration code from 
the notifier callback, like this:

	int ret = 0;

	switch (event) {
	case POST_RATE_CHANGE:
		ret = exynos4210_armclk_post_rate_change(...);
		break;
	case PRE_RATE_CHANGE:
		ret = exynos4210_armclk_pre_rate_change(...);
		break;
	}

	return notifier_from_errno(ret);

By the way, I wonder if some of this couldn't simply happen in 
.set_rate() op of this clock, since

> +
> +	/* pre-rate change. find out the divider values to use for clock data */
> +	while (armclk_data->prate != ndata->new_rate) {
> +		if (armclk_data->prate == 0)
> +			return NOTIFY_BAD;
> +		armclk_data++;
> +	}
> +
> +	div0 = armclk_data->div0;
> +	div1 = armclk_data->div1;

You should always use read-modify-write for such registers to preserve 
reserved bits. This will also clean a bit safe frequency activation, see 
below.

> +	if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
> +		div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
> +		div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
> +	}
> +
> +	/*
> +	 * if the new and old parent clock speed is less than the clock speed
> +	 * of the alternate parent, then it should be ensured that at no point
> +	 * the armclk speed is more than the old_prate until the dividers are
> +	 * set.
> +	 */
> +	need_safe_freq = ndata->old_rate < alt_prate &&
> +				ndata->new_rate < alt_prate;

Are you sure this condition is correct? The parent clock (PLL) alone 
doesn't fully determine the rate of ARM clock, because you are also 
changing div_core. So you can end up with PLL going down, while ARM 
clock going up, because the divisors are significantly lowered.

I think you should compare ARM clock rates here OR just remove div_core 
configuration, keeping it as 0 (divide by 1) all the time, except when 
safe frequency is active.

> +	if (need_safe_freq) {
> +		alt_div = _calc_div(alt_prate, ndata->old_rate);
> +		_exynos4210_set_armclk_div(base, alt_div);
> +		div0 |= alt_div;
> +	}


You could move div0 and div1 calculation (including reading original 
values of registers) here to remove "div0 |= alt_div;" line from the if 
above and fully isolate ARM divisor setup code from changing other divisors.

> +
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg | (1 << 16), base + SRC_CPU);

Don't you need to hold the samsung clock spinlock when writing to this 
register? It seems to control more muxes than just this one.

> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +		;
> +
> +	writel(div0, base + DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +	writel(div1, base + DIV_CPU1);
> +	while (readl(base + DIV_STAT_CPU1) != 0)
> +		;

You seem to always perform the configuration in pre rate change 
notifier, but original cpufreq code used to do it depending on whether 
the new frequency is less than old or not, e.g.

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);
         }
}

set_clkdiv does the following:
   1) set DIV_CPU0
   2) wait for DIV_STAT_CPU0
   3) set DIV_CPU1
   4) wait for DIV_STAT_CPU1

and set_apll:
   1) set parent to MPLL
   2) wait for MUX_STAT_CPU
   3) set APLL rate
   4) set parent to APLL
   5) wait for MUX_STAT_CPU

Note that higher index means lower frequency.

Btw. It would be nice to handle timeouts here as well, to prevent system 
lockups.

> +	return NOTIFY_OK;
> +
> +e4210_armclk_post_rate_change:
> +	/* post-rate change event, re-mux back to primary parent */
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> +			;

nit: Too many tabs.

Timeout would be nice too.

> +
> +	return NOTIFY_OK;
> +}
> +
> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long drate,
> +					unsigned long prate)
> +{
> +	struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
> +	void __iomem *base = armclk->ctrl_base + armclk->offset;
> +	unsigned long div;
> +
> +	div = drate < prate ? _calc_div(prate, drate) : 0;
> +	_exynos4210_set_armclk_div(base, div);
> +	return 0;

Hmm, here you are supposed to set exactly the rate given to you in drate 
argument. Core clock code calls your .round_rate() first and the rate 
returned by it is what .set_rate() gets as drate. You can safely assume 
that

> +}
> +
> +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,
> +};
> +
> +/*
> + * parse divider configuration data from dt for all the cpu clock domain
> + * clocks in exynos4210 and compatible SoC's.
> + */
> +static int __init exynos4210_armclk_parser(struct device_node *np, void **data)
> +{
> +	struct exynos4210_armclk_data *tdata;
> +	unsigned long cfg[10], row, col;
> +	const struct property *prop;
> +	const __be32 *val;
> +	u32 cells;
> +	int ret;
> +
> +	if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
> +		return -EINVAL;

The property should be prefixed with "#" as other properties defining 
number of cells.

Also you should check if cells value is correct, e.g. a number of cells 
supported

> +	prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
> +	if (!prop)
> +		return -EINVAL;
> +	if (!prop->value)
> +		return -EINVAL;
> +	if ((prop->length / sizeof(u32)) % cells)
> +		return -EINVAL;
> +	row = ((prop->length / sizeof(u32)) / cells) + 1;

Why + 1? Also the variable could be named in a bit more meaningful way, 
e.g. num_rows.

> +
> +	*data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
> +	if (!*data)
> +		ret = -ENOMEM;
> +	tdata = *data;
> +
> +	val = prop->value;
> +	for (; row > 1; row--, tdata++) {
> +		for (col = 0; col < cells; col++)
> +			cfg[col] = be32_to_cpup(val++);

You could use of_prop_next_u32() here.

> +
> +		tdata->prate = cfg[0] * 1000;
> +		tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5], cfg[4],
> +						cfg[3], cfg[2], cfg[1]);
> +		tdata->div1 = cells == 10 ?
> +				EXYNOS4210_DIV_CPU1(cfg[9], cfg[8], cfg[7]) :
> +				EXYNOS4210_DIV_CPU1(0, cfg[8], cfg[7]);
> +	}
> +	tdata->prate = 0;
> +	return 0;
> +}
> +
> +static const struct samsung_cpuclk_soc_data exynos4210_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x14200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct samsung_cpuclk_soc_data exynos5250_cpuclk_soc_data = {
> +	.parser = exynos4210_armclk_parser,
> +	.ops = &exynos4210_armclk_clk_ops,
> +	.offset = 0x200,
> +	.clk_cb = exynos4210_armclk_notifier_cb,
> +};
> +
> +static const struct of_device_id samsung_clock_ids_armclk[] = {
> +	{ .compatible = "samsung,exynos4210-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos4412-clock",
> +			.data = &exynos4210_cpuclk_soc_data, },
> +	{ .compatible = "samsung,exynos5250-clock",
> +			.data = &exynos5250_cpuclk_soc_data, },
> +	{ },
> +};
> +
> +/**
> + * samsung_register_arm_clock: register arm clock with ccf.
> + * @lookup_id: armclk clock output id for the clock controller.
> + * @parent: name of the parent clock for armclk.
> + * @base: base address of the clock controller from which armclk is generated.
> + * @np: device tree node pointer of the clock controller (optional).
> + * @ops: clock ops for this clock (optional)
> + */
> +int __init samsung_register_arm_clock(unsigned int lookup_id,
> +		const char **parent_names, unsigned int num_parents,
> +		void __iomem *base, struct device_node *np, struct clk_ops *ops)
> +{
> +	const struct of_device_id *match;
> +	const struct samsung_cpuclk_soc_data *data = NULL;
> +
> +	if (np) {
> +		match = of_match_node(samsung_clock_ids_armclk, np);
> +		data = match ? match->data : NULL;
> +	}

Since this is rather Exynos-specific and Exynos is DT-only, np being 
NULL would be simply an error.

Best regards,
Tomasz

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

* Re: [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-02-12 18:25     ` Tomasz Figa
@ 2014-02-13  7:58       ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-13  7:58 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: cpufreq, linux-arm-kernel, linux-samsung-soc, Mike Turquette,
	Shawn Guo, Kukjin Kim, Lukasz Majewski, Viresh Kumar, thomas.ab,
	Heiko Stübner

Hi Tomasz,

Thanks for your detailed review.

On Wed, Feb 12, 2014 at 11:55 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Thomas,
>
>
> On 07.02.2014 16:55, Thomas Abraham wrote:
>>
>> 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
>> configuration data for this clock is obtained from device tree. This
>> implementation is reusable for Exynos4x12 and Exynos5250 SoCs as well.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>   drivers/clk/samsung/Makefile  |    2 +-
>>   drivers/clk/samsung/clk-cpu.c |  409
>> +++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/samsung/clk.h     |    5 +
>>   3 files changed, 415 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/clk/samsung/clk-cpu.c
>
>
> [snip]
>
>
>> diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
>> new file mode 100644
>> index 0000000..673f620
>> --- /dev/null
>> +++ b/drivers/clk/samsung/clk-cpu.c
>> @@ -0,0 +1,409 @@
>
>
> [snip]
>
>
>> +#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
>> +
>> +#define MAX_DIV                        8
>> +
>> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
>> +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf)
>> + 1)
>
>
> Those are 3-bit dividers, so the mask should be rather 0x7, shouldn't it?

Yes, that is correct. I will fix this.

>
> Btw. Somehow I feel like this kind of macros is simply obfuscating code
> without any real benefits. Could you rewrite them to simply take the value
> of DIV_CPU0 register, without hiding readl behind the scenes?

Okay. I will change this.

>
>
>> +
>> +#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1, d0)                    \
>> +               ((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12) |    \
>> +                (d1 << 8) | (d0 <<  4))
>> +#define EXYNOS4210_DIV_CPU1(d2, d1, d0)
>> \
>> +               ((d2 << 8) | (d1 << 4) | (d0 << 0))
>> +
>> +#define EXYNOS4210_DIV1_HPM_MASK       ((0x7 << 0) | (0x7 << 4))
>> +#define EXYNOS4210_MUX_HPM_MASK                (1 << 20)
>
>
> [snip]
>
>
>> +/* common round rate callback useable for all types of cpu clocks */
>> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
>> +                       unsigned long drate, unsigned long *prate)
>> +{
>> +       struct clk *parent = __clk_get_parent(hw->clk);
>> +       unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
>> +       unsigned long t_prate, best_div = 1;
>> +       unsigned long delta, min_delta = UINT_MAX;
>> +
>> +       do {
>> +               t_prate = __clk_round_rate(parent, drate * best_div);
>> +               delta = drate - (t_prate / best_div);
>> +               if (delta < min_delta) {
>> +                       *prate = t_prate;
>> +                       min_delta = delta;
>> +               }
>> +               if (!delta)
>> +                       break;
>> +               best_div++;
>> +       } while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
>> +
>> +       return t_prate / best_div;
>> +}
>
>
> I think there is something wrong with the code above. You increment best_div
> in every iteration of the loop and use it to calculate the final best
> frequency. Shouldn't best_div be the divisor which was found to give the
> least delta and so the loop should rather iterate on a different variable
> and store best_div only if (delta < min_delta) condition is true?

This function finds out the best parent frequency (APLL in this case)
which when divided with some divider value provides the the closest
possible drate. Probably, the name best_div is misleading since there
is no need to know the value of best_div outside this function.

>
> Anyway, I wonder if you couldn't somehow reuse the code from
> drivers/clk/clk-divider.c...

Yes, there are some similarities between these but they are not
entirely the same.

>
>
>> +
>> +static unsigned long _calc_div(unsigned long prate, unsigned long drate)
>> +{
>> +       unsigned long div = prate / drate;
>> +
>> +       WARN_ON(div >= MAX_DIV);
>> +       return (!(prate % drate)) ? div-- : div;
>> +}
>> +
>> +/* helper function to register a cpu clock */
>> +static int __init samsung_cpuclk_register(unsigned int lookup_id,
>
>
> Isn't the name a bit too generic? I'd say it should be
> exynos_cpuclk_register(), since the implementation is rather Exynos specific
> anyway.

The implementation of the cpu clock type is supposed to be usable on
all Samsung SoCs starting from s3c24xx onwards. I should have probably
stated that explicitly.

>
>
>> +               const char *name, const char **parents,
>> +               unsigned int num_parents, void __iomem *base,
>> +               const struct samsung_cpuclk_soc_data *soc_data,
>> +               struct device_node *np, const struct clk_ops *ops)
>> +{
>> +       struct samsung_cpuclk *cpuclk;
>> +       struct clk_init_data init;
>> +       struct clk *clk;
>> +       int ret;
>> +
>> +       cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
>> +       if (!cpuclk) {
>> +               pr_err("%s: could not allocate memory for %s clock\n",
>> +                                       __func__, name);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       init.name = name;
>> +       init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
>
>
> Why CLK_GET_RATE_NOCACHE? There is only one entity that can change rate of
> this clock and it is this clock driver, so it can update the cache on any
> change.

Right, will remove this flag.

>
>
>> +       init.parent_names = parents;
>> +       init.num_parents = 1;
>
>
> I believe this clock should take two clocks as its parents, because it can
> dynamically switch between mout_apll and mout_mpll using mout_core mux.

Since the mout_core mux is encapsulated into the cpu clock type, the
dynamic switching is not allowed from CCF API. The switching is fully
controlled by the cpu clock type when required and hence the CCF need
not be told about 2 parents.

>
>
>> +       init.ops = ops;
>> +
>> +       cpuclk->hw.init = &init;
>> +       cpuclk->ctrl_base = base;
>> +
>> +       if (soc_data && soc_data->parser) {
>
>
> Is it even possible to instantiate this clock without soc_data and parser
> function? Shouldn't it simply bail out instead?

Yes, the intent was to allow Samsung cpu clock type to usable on
non-DT platforms as well. If a platform has soc_data, then the parser
can be called.

>
>
>> +               ret = soc_data->parser(np, &cpuclk->data);
>> +               if (ret) {
>> +                       pr_err("%s: error %d in parsing %s clock data",
>> +                                       __func__, ret, name);
>> +                       ret = -EINVAL;
>> +                       goto free_cpuclk;
>> +               }
>> +               cpuclk->offset = soc_data->offset;
>> +               init.ops = soc_data->ops;
>> +       }
>> +
>> +       if (soc_data && soc_data->clk_cb) {
>
>
> Same here. Does it make any sense to instantiate this clock without a
> notifier callback?
>
>
>> +               cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
>> +               if (clk_notifier_register(__clk_lookup(parents[0]),
>> +                               &cpuclk->clk_nb)) {
>> +                       pr_err("%s: failed to register clock notifier for
>> %s\n",
>> +                                       __func__, name);
>> +                       goto free_cpuclk_data;
>> +               }
>> +       }
>> +
>> +       if (num_parents == 2) {
>
>
> When num_parents could be other than 2?

If any Samsung SoC needs no alternate parent clock when changing armclk rate.

>
>
>> +               cpuclk->alt_parent = __clk_lookup(parents[1]);
>> +               if (!cpuclk->alt_parent) {
>> +                       pr_err("%s: could not lookup alternate parent
>> %s\n",
>> +                                       __func__, parents[1]);
>> +                       ret = -EINVAL;
>> +                       goto free_cpuclk_data;
>> +               }
>> +       }
>> +
>> +       clk = clk_register(NULL, &cpuclk->hw);
>> +       if (IS_ERR(clk)) {
>> +               pr_err("%s: could not register cpuclk %s\n", __func__,
>> name);
>> +               ret = PTR_ERR(clk);
>> +               goto free_cpuclk_data;
>> +       }
>> +
>> +       samsung_clk_add_lookup(clk, lookup_id);
>> +       return 0;
>> +
>> +free_cpuclk_data:
>> +       kfree(cpuclk->data);
>> +free_cpuclk:
>> +       kfree(cpuclk);
>> +       return ret;
>> +}
>> +
>> +static inline void _exynos4210_set_armclk_div(void __iomem *base,
>> +                       unsigned long div)
>
>
> I'd say it would be better to leave the decision about inlining to the
> compiler.

Okay.

>
>
>> +{
>> +       writel((readl(base + DIV_CPU0) & ~0xf) | div, base + DIV_CPU0);
>
>
> CORE_RATIO bitfield is 3-bit wide.

Right, will fix.

>
>
>> +       while (readl(base + DIV_STAT_CPU0) != 0)
>> +               ;
>
>
> Wouldn't it be better to add some timeout and print an error to make sure
> that even if something wrong happens the user will know that it happened?

Okay, will add timeout.

>
>
>> +}
>> +
>> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
>> +                               unsigned long parent_rate)
>> +{
>> +       struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
>> +       void __iomem *base = armclk->ctrl_base + armclk->offset;
>> +
>> +       return parent_rate / EXYNOS4210_ARM_DIV1(base) /
>> +                               EXYNOS4210_ARM_DIV2(base);
>
>
> The code would be more readable if you read the register to a temporary
> variable using readl() directly and then accessing its contents.

Okay.

>
>
>> +}
>> +
>> +/*
>> + * This clock notifier is called when the frequency of the parent clock
>> + * of armclk is to be changed. This notifier handles the setting up all
>> + * the divider clocks, remux to temporary parent and handling the safe
>> + * frequency levels when using temporary parent.
>> + */
>> +static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
>> +                               unsigned long event, void *data)
>> +{
>> +       struct clk_notifier_data *ndata = data;
>> +       struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
>> +       struct exynos4210_armclk_data *armclk_data;
>> +       unsigned long alt_prate, alt_div, div0, div1, mux_reg;
>> +       void __iomem *base;
>> +       bool need_safe_freq;
>> +
>> +       armclk_data = armclk->data;
>> +       base = armclk->ctrl_base + armclk->offset;
>> +       alt_prate = clk_get_rate(armclk->alt_parent);
>> +
>> +       if (event == POST_RATE_CHANGE)
>> +               goto e4210_armclk_post_rate_change;
>
>
> This would look better if you separated the main configuration code from the
> notifier callback, like this:
>
>         int ret = 0;
>
>         switch (event) {
>         case POST_RATE_CHANGE:
>                 ret = exynos4210_armclk_post_rate_change(...);
>                 break;
>         case PRE_RATE_CHANGE:
>                 ret = exynos4210_armclk_pre_rate_change(...);
>                 break;
>         }
>
>         return notifier_from_errno(ret);

Okay.

>
> By the way, I wonder if some of this couldn't simply happen in .set_rate()
> op of this clock, since
>
>
>> +
>> +       /* pre-rate change. find out the divider values to use for clock
>> data */
>> +       while (armclk_data->prate != ndata->new_rate) {
>> +               if (armclk_data->prate == 0)
>> +                       return NOTIFY_BAD;
>> +               armclk_data++;
>> +       }
>> +
>> +       div0 = armclk_data->div0;
>> +       div1 = armclk_data->div1;
>
>
> You should always use read-modify-write for such registers to preserve
> reserved bits. This will also clean a bit safe frequency activation, see
> below.
>
>
>> +       if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
>> +               div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
>> +               div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
>> +       }
>> +
>> +       /*
>> +        * if the new and old parent clock speed is less than the clock
>> speed
>> +        * of the alternate parent, then it should be ensured that at no
>> point
>> +        * the armclk speed is more than the old_prate until the dividers
>> are
>> +        * set.
>> +        */
>> +       need_safe_freq = ndata->old_rate < alt_prate &&
>> +                               ndata->new_rate < alt_prate;
>
>
> Are you sure this condition is correct? The parent clock (PLL) alone doesn't
> fully determine the rate of ARM clock, because you are also changing
> div_core. So you can end up with PLL going down, while ARM clock going up,
> because the divisors are significantly lowered.

Interesting! I did not think about this. Will fix it.

>
> I think you should compare ARM clock rates here OR just remove div_core
> configuration, keeping it as 0 (divide by 1) all the time, except when safe
> frequency is active.

I would like to keep have div_core configuration, since it gives more
options for armclk, not just limited to PLL speeds.

>
>
>> +       if (need_safe_freq) {
>> +               alt_div = _calc_div(alt_prate, ndata->old_rate);
>> +               _exynos4210_set_armclk_div(base, alt_div);
>> +               div0 |= alt_div;
>> +       }
>
>
>
> You could move div0 and div1 calculation (including reading original values
> of registers) here to remove "div0 |= alt_div;" line from the if above and
> fully isolate ARM divisor setup code from changing other divisors.
>
>
>> +
>> +       mux_reg = readl(base + SRC_CPU);
>> +       writel(mux_reg | (1 << 16), base + SRC_CPU);
>
>
> Don't you need to hold the samsung clock spinlock when writing to this
> register? It seems to control more muxes than just this one.

Right, will fix it.

>
>
>> +       while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
>> +               ;
>> +
>> +       writel(div0, base + DIV_CPU0);
>> +       while (readl(base + DIV_STAT_CPU0) != 0)
>> +               ;
>> +       writel(div1, base + DIV_CPU1);
>> +       while (readl(base + DIV_STAT_CPU1) != 0)
>> +               ;
>
>
> You seem to always perform the configuration in pre rate change notifier,
> but original cpufreq code used to do it depending on whether the new
> frequency is less than old or not, e.g.

Yes, but with the clock notifier callback, we need not do it like below.

>
> 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);
>         }
> }
>
> set_clkdiv does the following:
>   1) set DIV_CPU0
>   2) wait for DIV_STAT_CPU0
>   3) set DIV_CPU1
>   4) wait for DIV_STAT_CPU1
>
> and set_apll:
>   1) set parent to MPLL
>   2) wait for MUX_STAT_CPU
>   3) set APLL rate
>   4) set parent to APLL
>   5) wait for MUX_STAT_CPU
>
> Note that higher index means lower frequency.
>
> Btw. It would be nice to handle timeouts here as well, to prevent system
> lockups.

Okay.

>
>
>> +       return NOTIFY_OK;
>> +
>> +e4210_armclk_post_rate_change:
>> +       /* post-rate change event, re-mux back to primary parent */
>> +       mux_reg = readl(base + SRC_CPU);
>> +       writel(mux_reg & ~(1 << 16), base + SRC_CPU);
>> +       while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
>> +                       ;
>
>
> nit: Too many tabs.
>
> Timeout would be nice too.
>
>
>> +
>> +       return NOTIFY_OK;
>> +}
>> +
>> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long
>> drate,
>> +                                       unsigned long prate)
>> +{
>> +       struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
>> +       void __iomem *base = armclk->ctrl_base + armclk->offset;
>> +       unsigned long div;
>> +
>> +       div = drate < prate ? _calc_div(prate, drate) : 0;
>> +       _exynos4210_set_armclk_div(base, div);
>> +       return 0;
>
>
> Hmm, here you are supposed to set exactly the rate given to you in drate
> argument. Core clock code calls your .round_rate() first and the rate
> returned by it is what .set_rate() gets as drate. You can safely assume that
>
>
>> +}
>> +
>> +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,
>> +};
>> +
>> +/*
>> + * parse divider configuration data from dt for all the cpu clock domain
>> + * clocks in exynos4210 and compatible SoC's.
>> + */
>> +static int __init exynos4210_armclk_parser(struct device_node *np, void
>> **data)
>> +{
>> +       struct exynos4210_armclk_data *tdata;
>> +       unsigned long cfg[10], row, col;
>> +       const struct property *prop;
>> +       const __be32 *val;
>> +       u32 cells;
>> +       int ret;
>> +
>> +       if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
>> +               return -EINVAL;
>
>
> The property should be prefixed with "#" as other properties defining number
> of cells.

Isn't # a unnecessary requirement here. The old dt bindings used to
have it and I am not sure in what way it helps. And this is a samsung
specific property. Anyways, I do not have any particular preference on
this.

>
> Also you should check if cells value is correct, e.g. a number of cells
> supported

Okay.

>
>
>> +       prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
>> +       if (!prop)
>> +               return -EINVAL;
>> +       if (!prop->value)
>> +               return -EINVAL;
>> +       if ((prop->length / sizeof(u32)) % cells)
>> +               return -EINVAL;
>> +       row = ((prop->length / sizeof(u32)) / cells) + 1;
>
>
> Why + 1? Also the variable could be named in a bit more meaningful way, e.g.
> num_rows.

+1 since this is a zero terminated table. Will change the variable name.

>
>
>> +
>> +       *data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
>> +       if (!*data)
>> +               ret = -ENOMEM;
>> +       tdata = *data;
>> +
>> +       val = prop->value;
>> +       for (; row > 1; row--, tdata++) {
>> +               for (col = 0; col < cells; col++)
>> +                       cfg[col] = be32_to_cpup(val++);
>
>
> You could use of_prop_next_u32() here.

Okay.

>
>
>> +
>> +               tdata->prate = cfg[0] * 1000;
>> +               tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5], cfg[4],
>> +                                               cfg[3], cfg[2], cfg[1]);
>> +               tdata->div1 = cells == 10 ?
>> +                               EXYNOS4210_DIV_CPU1(cfg[9], cfg[8],
>> cfg[7]) :
>> +                               EXYNOS4210_DIV_CPU1(0, cfg[8], cfg[7]);
>> +       }
>> +       tdata->prate = 0;
>> +       return 0;
>> +}
>> +
>> +static const struct samsung_cpuclk_soc_data exynos4210_cpuclk_soc_data =
>> {
>> +       .parser = exynos4210_armclk_parser,
>> +       .ops = &exynos4210_armclk_clk_ops,
>> +       .offset = 0x14200,
>> +       .clk_cb = exynos4210_armclk_notifier_cb,
>> +};
>> +
>> +static const struct samsung_cpuclk_soc_data exynos5250_cpuclk_soc_data =
>> {
>> +       .parser = exynos4210_armclk_parser,
>> +       .ops = &exynos4210_armclk_clk_ops,
>> +       .offset = 0x200,
>> +       .clk_cb = exynos4210_armclk_notifier_cb,
>> +};
>> +
>> +static const struct of_device_id samsung_clock_ids_armclk[] = {
>> +       { .compatible = "samsung,exynos4210-clock",
>> +                       .data = &exynos4210_cpuclk_soc_data, },
>> +       { .compatible = "samsung,exynos4412-clock",
>> +                       .data = &exynos4210_cpuclk_soc_data, },
>> +       { .compatible = "samsung,exynos5250-clock",
>> +                       .data = &exynos5250_cpuclk_soc_data, },
>> +       { },
>> +};
>> +
>> +/**
>> + * samsung_register_arm_clock: register arm clock with ccf.
>> + * @lookup_id: armclk clock output id for the clock controller.
>> + * @parent: name of the parent clock for armclk.
>> + * @base: base address of the clock controller from which armclk is
>> generated.
>> + * @np: device tree node pointer of the clock controller (optional).
>> + * @ops: clock ops for this clock (optional)
>> + */
>> +int __init samsung_register_arm_clock(unsigned int lookup_id,
>> +               const char **parent_names, unsigned int num_parents,
>> +               void __iomem *base, struct device_node *np, struct clk_ops
>> *ops)
>> +{
>> +       const struct of_device_id *match;
>> +       const struct samsung_cpuclk_soc_data *data = NULL;
>> +
>> +       if (np) {
>> +               match = of_match_node(samsung_clock_ids_armclk, np);
>> +               data = match ? match->data : NULL;
>> +       }
>
>
> Since this is rather Exynos-specific and Exynos is DT-only, np being NULL
> would be simply an error.

The cpu clock type is usable for not-dt samsung platform also.

>
> Best regards,
> Tomasz

Thanks for your review.

Regards,
Thomas.

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

* [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
@ 2014-02-13  7:58       ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-13  7:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tomasz,

Thanks for your detailed review.

On Wed, Feb 12, 2014 at 11:55 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Thomas,
>
>
> On 07.02.2014 16:55, Thomas Abraham wrote:
>>
>> 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
>> configuration data for this clock is obtained from device tree. This
>> implementation is reusable for Exynos4x12 and Exynos5250 SoCs as well.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>   drivers/clk/samsung/Makefile  |    2 +-
>>   drivers/clk/samsung/clk-cpu.c |  409
>> +++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/samsung/clk.h     |    5 +
>>   3 files changed, 415 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/clk/samsung/clk-cpu.c
>
>
> [snip]
>
>
>> diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
>> new file mode 100644
>> index 0000000..673f620
>> --- /dev/null
>> +++ b/drivers/clk/samsung/clk-cpu.c
>> @@ -0,0 +1,409 @@
>
>
> [snip]
>
>
>> +#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
>> +
>> +#define MAX_DIV                        8
>> +
>> +#define EXYNOS4210_ARM_DIV1(base) ((readl(base + DIV_CPU0) & 0xf) + 1)
>> +#define EXYNOS4210_ARM_DIV2(base) (((readl(base + DIV_CPU0) >> 28) & 0xf)
>> + 1)
>
>
> Those are 3-bit dividers, so the mask should be rather 0x7, shouldn't it?

Yes, that is correct. I will fix this.

>
> Btw. Somehow I feel like this kind of macros is simply obfuscating code
> without any real benefits. Could you rewrite them to simply take the value
> of DIV_CPU0 register, without hiding readl behind the scenes?

Okay. I will change this.

>
>
>> +
>> +#define EXYNOS4210_DIV_CPU0(d5, d4, d3, d2, d1, d0)                    \
>> +               ((d5 << 24) | (d4 << 20) | (d3 << 16) | (d2 << 12) |    \
>> +                (d1 << 8) | (d0 <<  4))
>> +#define EXYNOS4210_DIV_CPU1(d2, d1, d0)
>> \
>> +               ((d2 << 8) | (d1 << 4) | (d0 << 0))
>> +
>> +#define EXYNOS4210_DIV1_HPM_MASK       ((0x7 << 0) | (0x7 << 4))
>> +#define EXYNOS4210_MUX_HPM_MASK                (1 << 20)
>
>
> [snip]
>
>
>> +/* common round rate callback useable for all types of cpu clocks */
>> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
>> +                       unsigned long drate, unsigned long *prate)
>> +{
>> +       struct clk *parent = __clk_get_parent(hw->clk);
>> +       unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
>> +       unsigned long t_prate, best_div = 1;
>> +       unsigned long delta, min_delta = UINT_MAX;
>> +
>> +       do {
>> +               t_prate = __clk_round_rate(parent, drate * best_div);
>> +               delta = drate - (t_prate / best_div);
>> +               if (delta < min_delta) {
>> +                       *prate = t_prate;
>> +                       min_delta = delta;
>> +               }
>> +               if (!delta)
>> +                       break;
>> +               best_div++;
>> +       } while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
>> +
>> +       return t_prate / best_div;
>> +}
>
>
> I think there is something wrong with the code above. You increment best_div
> in every iteration of the loop and use it to calculate the final best
> frequency. Shouldn't best_div be the divisor which was found to give the
> least delta and so the loop should rather iterate on a different variable
> and store best_div only if (delta < min_delta) condition is true?

This function finds out the best parent frequency (APLL in this case)
which when divided with some divider value provides the the closest
possible drate. Probably, the name best_div is misleading since there
is no need to know the value of best_div outside this function.

>
> Anyway, I wonder if you couldn't somehow reuse the code from
> drivers/clk/clk-divider.c...

Yes, there are some similarities between these but they are not
entirely the same.

>
>
>> +
>> +static unsigned long _calc_div(unsigned long prate, unsigned long drate)
>> +{
>> +       unsigned long div = prate / drate;
>> +
>> +       WARN_ON(div >= MAX_DIV);
>> +       return (!(prate % drate)) ? div-- : div;
>> +}
>> +
>> +/* helper function to register a cpu clock */
>> +static int __init samsung_cpuclk_register(unsigned int lookup_id,
>
>
> Isn't the name a bit too generic? I'd say it should be
> exynos_cpuclk_register(), since the implementation is rather Exynos specific
> anyway.

The implementation of the cpu clock type is supposed to be usable on
all Samsung SoCs starting from s3c24xx onwards. I should have probably
stated that explicitly.

>
>
>> +               const char *name, const char **parents,
>> +               unsigned int num_parents, void __iomem *base,
>> +               const struct samsung_cpuclk_soc_data *soc_data,
>> +               struct device_node *np, const struct clk_ops *ops)
>> +{
>> +       struct samsung_cpuclk *cpuclk;
>> +       struct clk_init_data init;
>> +       struct clk *clk;
>> +       int ret;
>> +
>> +       cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
>> +       if (!cpuclk) {
>> +               pr_err("%s: could not allocate memory for %s clock\n",
>> +                                       __func__, name);
>> +               return -ENOMEM;
>> +       }
>> +
>> +       init.name = name;
>> +       init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT;
>
>
> Why CLK_GET_RATE_NOCACHE? There is only one entity that can change rate of
> this clock and it is this clock driver, so it can update the cache on any
> change.

Right, will remove this flag.

>
>
>> +       init.parent_names = parents;
>> +       init.num_parents = 1;
>
>
> I believe this clock should take two clocks as its parents, because it can
> dynamically switch between mout_apll and mout_mpll using mout_core mux.

Since the mout_core mux is encapsulated into the cpu clock type, the
dynamic switching is not allowed from CCF API. The switching is fully
controlled by the cpu clock type when required and hence the CCF need
not be told about 2 parents.

>
>
>> +       init.ops = ops;
>> +
>> +       cpuclk->hw.init = &init;
>> +       cpuclk->ctrl_base = base;
>> +
>> +       if (soc_data && soc_data->parser) {
>
>
> Is it even possible to instantiate this clock without soc_data and parser
> function? Shouldn't it simply bail out instead?

Yes, the intent was to allow Samsung cpu clock type to usable on
non-DT platforms as well. If a platform has soc_data, then the parser
can be called.

>
>
>> +               ret = soc_data->parser(np, &cpuclk->data);
>> +               if (ret) {
>> +                       pr_err("%s: error %d in parsing %s clock data",
>> +                                       __func__, ret, name);
>> +                       ret = -EINVAL;
>> +                       goto free_cpuclk;
>> +               }
>> +               cpuclk->offset = soc_data->offset;
>> +               init.ops = soc_data->ops;
>> +       }
>> +
>> +       if (soc_data && soc_data->clk_cb) {
>
>
> Same here. Does it make any sense to instantiate this clock without a
> notifier callback?
>
>
>> +               cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
>> +               if (clk_notifier_register(__clk_lookup(parents[0]),
>> +                               &cpuclk->clk_nb)) {
>> +                       pr_err("%s: failed to register clock notifier for
>> %s\n",
>> +                                       __func__, name);
>> +                       goto free_cpuclk_data;
>> +               }
>> +       }
>> +
>> +       if (num_parents == 2) {
>
>
> When num_parents could be other than 2?

If any Samsung SoC needs no alternate parent clock when changing armclk rate.

>
>
>> +               cpuclk->alt_parent = __clk_lookup(parents[1]);
>> +               if (!cpuclk->alt_parent) {
>> +                       pr_err("%s: could not lookup alternate parent
>> %s\n",
>> +                                       __func__, parents[1]);
>> +                       ret = -EINVAL;
>> +                       goto free_cpuclk_data;
>> +               }
>> +       }
>> +
>> +       clk = clk_register(NULL, &cpuclk->hw);
>> +       if (IS_ERR(clk)) {
>> +               pr_err("%s: could not register cpuclk %s\n", __func__,
>> name);
>> +               ret = PTR_ERR(clk);
>> +               goto free_cpuclk_data;
>> +       }
>> +
>> +       samsung_clk_add_lookup(clk, lookup_id);
>> +       return 0;
>> +
>> +free_cpuclk_data:
>> +       kfree(cpuclk->data);
>> +free_cpuclk:
>> +       kfree(cpuclk);
>> +       return ret;
>> +}
>> +
>> +static inline void _exynos4210_set_armclk_div(void __iomem *base,
>> +                       unsigned long div)
>
>
> I'd say it would be better to leave the decision about inlining to the
> compiler.

Okay.

>
>
>> +{
>> +       writel((readl(base + DIV_CPU0) & ~0xf) | div, base + DIV_CPU0);
>
>
> CORE_RATIO bitfield is 3-bit wide.

Right, will fix.

>
>
>> +       while (readl(base + DIV_STAT_CPU0) != 0)
>> +               ;
>
>
> Wouldn't it be better to add some timeout and print an error to make sure
> that even if something wrong happens the user will know that it happened?

Okay, will add timeout.

>
>
>> +}
>> +
>> +static unsigned long exynos4210_armclk_recalc_rate(struct clk_hw *hw,
>> +                               unsigned long parent_rate)
>> +{
>> +       struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
>> +       void __iomem *base = armclk->ctrl_base + armclk->offset;
>> +
>> +       return parent_rate / EXYNOS4210_ARM_DIV1(base) /
>> +                               EXYNOS4210_ARM_DIV2(base);
>
>
> The code would be more readable if you read the register to a temporary
> variable using readl() directly and then accessing its contents.

Okay.

>
>
>> +}
>> +
>> +/*
>> + * This clock notifier is called when the frequency of the parent clock
>> + * of armclk is to be changed. This notifier handles the setting up all
>> + * the divider clocks, remux to temporary parent and handling the safe
>> + * frequency levels when using temporary parent.
>> + */
>> +static int exynos4210_armclk_notifier_cb(struct notifier_block *nb,
>> +                               unsigned long event, void *data)
>> +{
>> +       struct clk_notifier_data *ndata = data;
>> +       struct samsung_cpuclk *armclk = to_samsung_cpuclk_nb(nb);
>> +       struct exynos4210_armclk_data *armclk_data;
>> +       unsigned long alt_prate, alt_div, div0, div1, mux_reg;
>> +       void __iomem *base;
>> +       bool need_safe_freq;
>> +
>> +       armclk_data = armclk->data;
>> +       base = armclk->ctrl_base + armclk->offset;
>> +       alt_prate = clk_get_rate(armclk->alt_parent);
>> +
>> +       if (event == POST_RATE_CHANGE)
>> +               goto e4210_armclk_post_rate_change;
>
>
> This would look better if you separated the main configuration code from the
> notifier callback, like this:
>
>         int ret = 0;
>
>         switch (event) {
>         case POST_RATE_CHANGE:
>                 ret = exynos4210_armclk_post_rate_change(...);
>                 break;
>         case PRE_RATE_CHANGE:
>                 ret = exynos4210_armclk_pre_rate_change(...);
>                 break;
>         }
>
>         return notifier_from_errno(ret);

Okay.

>
> By the way, I wonder if some of this couldn't simply happen in .set_rate()
> op of this clock, since
>
>
>> +
>> +       /* pre-rate change. find out the divider values to use for clock
>> data */
>> +       while (armclk_data->prate != ndata->new_rate) {
>> +               if (armclk_data->prate == 0)
>> +                       return NOTIFY_BAD;
>> +               armclk_data++;
>> +       }
>> +
>> +       div0 = armclk_data->div0;
>> +       div1 = armclk_data->div1;
>
>
> You should always use read-modify-write for such registers to preserve
> reserved bits. This will also clean a bit safe frequency activation, see
> below.
>
>
>> +       if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
>> +               div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
>> +               div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
>> +       }
>> +
>> +       /*
>> +        * if the new and old parent clock speed is less than the clock
>> speed
>> +        * of the alternate parent, then it should be ensured that at no
>> point
>> +        * the armclk speed is more than the old_prate until the dividers
>> are
>> +        * set.
>> +        */
>> +       need_safe_freq = ndata->old_rate < alt_prate &&
>> +                               ndata->new_rate < alt_prate;
>
>
> Are you sure this condition is correct? The parent clock (PLL) alone doesn't
> fully determine the rate of ARM clock, because you are also changing
> div_core. So you can end up with PLL going down, while ARM clock going up,
> because the divisors are significantly lowered.

Interesting! I did not think about this. Will fix it.

>
> I think you should compare ARM clock rates here OR just remove div_core
> configuration, keeping it as 0 (divide by 1) all the time, except when safe
> frequency is active.

I would like to keep have div_core configuration, since it gives more
options for armclk, not just limited to PLL speeds.

>
>
>> +       if (need_safe_freq) {
>> +               alt_div = _calc_div(alt_prate, ndata->old_rate);
>> +               _exynos4210_set_armclk_div(base, alt_div);
>> +               div0 |= alt_div;
>> +       }
>
>
>
> You could move div0 and div1 calculation (including reading original values
> of registers) here to remove "div0 |= alt_div;" line from the if above and
> fully isolate ARM divisor setup code from changing other divisors.
>
>
>> +
>> +       mux_reg = readl(base + SRC_CPU);
>> +       writel(mux_reg | (1 << 16), base + SRC_CPU);
>
>
> Don't you need to hold the samsung clock spinlock when writing to this
> register? It seems to control more muxes than just this one.

Right, will fix it.

>
>
>> +       while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
>> +               ;
>> +
>> +       writel(div0, base + DIV_CPU0);
>> +       while (readl(base + DIV_STAT_CPU0) != 0)
>> +               ;
>> +       writel(div1, base + DIV_CPU1);
>> +       while (readl(base + DIV_STAT_CPU1) != 0)
>> +               ;
>
>
> You seem to always perform the configuration in pre rate change notifier,
> but original cpufreq code used to do it depending on whether the new
> frequency is less than old or not, e.g.

Yes, but with the clock notifier callback, we need not do it like below.

>
> 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);
>         }
> }
>
> set_clkdiv does the following:
>   1) set DIV_CPU0
>   2) wait for DIV_STAT_CPU0
>   3) set DIV_CPU1
>   4) wait for DIV_STAT_CPU1
>
> and set_apll:
>   1) set parent to MPLL
>   2) wait for MUX_STAT_CPU
>   3) set APLL rate
>   4) set parent to APLL
>   5) wait for MUX_STAT_CPU
>
> Note that higher index means lower frequency.
>
> Btw. It would be nice to handle timeouts here as well, to prevent system
> lockups.

Okay.

>
>
>> +       return NOTIFY_OK;
>> +
>> +e4210_armclk_post_rate_change:
>> +       /* post-rate change event, re-mux back to primary parent */
>> +       mux_reg = readl(base + SRC_CPU);
>> +       writel(mux_reg & ~(1 << 16), base + SRC_CPU);
>> +       while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
>> +                       ;
>
>
> nit: Too many tabs.
>
> Timeout would be nice too.
>
>
>> +
>> +       return NOTIFY_OK;
>> +}
>> +
>> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned long
>> drate,
>> +                                       unsigned long prate)
>> +{
>> +       struct samsung_cpuclk *armclk = to_samsung_cpuclk_hw(hw);
>> +       void __iomem *base = armclk->ctrl_base + armclk->offset;
>> +       unsigned long div;
>> +
>> +       div = drate < prate ? _calc_div(prate, drate) : 0;
>> +       _exynos4210_set_armclk_div(base, div);
>> +       return 0;
>
>
> Hmm, here you are supposed to set exactly the rate given to you in drate
> argument. Core clock code calls your .round_rate() first and the rate
> returned by it is what .set_rate() gets as drate. You can safely assume that
>
>
>> +}
>> +
>> +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,
>> +};
>> +
>> +/*
>> + * parse divider configuration data from dt for all the cpu clock domain
>> + * clocks in exynos4210 and compatible SoC's.
>> + */
>> +static int __init exynos4210_armclk_parser(struct device_node *np, void
>> **data)
>> +{
>> +       struct exynos4210_armclk_data *tdata;
>> +       unsigned long cfg[10], row, col;
>> +       const struct property *prop;
>> +       const __be32 *val;
>> +       u32 cells;
>> +       int ret;
>> +
>> +       if (of_property_read_u32(np, "samsung,armclk-cells", &cells))
>> +               return -EINVAL;
>
>
> The property should be prefixed with "#" as other properties defining number
> of cells.

Isn't # a unnecessary requirement here. The old dt bindings used to
have it and I am not sure in what way it helps. And this is a samsung
specific property. Anyways, I do not have any particular preference on
this.

>
> Also you should check if cells value is correct, e.g. a number of cells
> supported

Okay.

>
>
>> +       prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
>> +       if (!prop)
>> +               return -EINVAL;
>> +       if (!prop->value)
>> +               return -EINVAL;
>> +       if ((prop->length / sizeof(u32)) % cells)
>> +               return -EINVAL;
>> +       row = ((prop->length / sizeof(u32)) / cells) + 1;
>
>
> Why + 1? Also the variable could be named in a bit more meaningful way, e.g.
> num_rows.

+1 since this is a zero terminated table. Will change the variable name.

>
>
>> +
>> +       *data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
>> +       if (!*data)
>> +               ret = -ENOMEM;
>> +       tdata = *data;
>> +
>> +       val = prop->value;
>> +       for (; row > 1; row--, tdata++) {
>> +               for (col = 0; col < cells; col++)
>> +                       cfg[col] = be32_to_cpup(val++);
>
>
> You could use of_prop_next_u32() here.

Okay.

>
>
>> +
>> +               tdata->prate = cfg[0] * 1000;
>> +               tdata->div0 = EXYNOS4210_DIV_CPU0(cfg[6], cfg[5], cfg[4],
>> +                                               cfg[3], cfg[2], cfg[1]);
>> +               tdata->div1 = cells == 10 ?
>> +                               EXYNOS4210_DIV_CPU1(cfg[9], cfg[8],
>> cfg[7]) :
>> +                               EXYNOS4210_DIV_CPU1(0, cfg[8], cfg[7]);
>> +       }
>> +       tdata->prate = 0;
>> +       return 0;
>> +}
>> +
>> +static const struct samsung_cpuclk_soc_data exynos4210_cpuclk_soc_data =
>> {
>> +       .parser = exynos4210_armclk_parser,
>> +       .ops = &exynos4210_armclk_clk_ops,
>> +       .offset = 0x14200,
>> +       .clk_cb = exynos4210_armclk_notifier_cb,
>> +};
>> +
>> +static const struct samsung_cpuclk_soc_data exynos5250_cpuclk_soc_data =
>> {
>> +       .parser = exynos4210_armclk_parser,
>> +       .ops = &exynos4210_armclk_clk_ops,
>> +       .offset = 0x200,
>> +       .clk_cb = exynos4210_armclk_notifier_cb,
>> +};
>> +
>> +static const struct of_device_id samsung_clock_ids_armclk[] = {
>> +       { .compatible = "samsung,exynos4210-clock",
>> +                       .data = &exynos4210_cpuclk_soc_data, },
>> +       { .compatible = "samsung,exynos4412-clock",
>> +                       .data = &exynos4210_cpuclk_soc_data, },
>> +       { .compatible = "samsung,exynos5250-clock",
>> +                       .data = &exynos5250_cpuclk_soc_data, },
>> +       { },
>> +};
>> +
>> +/**
>> + * samsung_register_arm_clock: register arm clock with ccf.
>> + * @lookup_id: armclk clock output id for the clock controller.
>> + * @parent: name of the parent clock for armclk.
>> + * @base: base address of the clock controller from which armclk is
>> generated.
>> + * @np: device tree node pointer of the clock controller (optional).
>> + * @ops: clock ops for this clock (optional)
>> + */
>> +int __init samsung_register_arm_clock(unsigned int lookup_id,
>> +               const char **parent_names, unsigned int num_parents,
>> +               void __iomem *base, struct device_node *np, struct clk_ops
>> *ops)
>> +{
>> +       const struct of_device_id *match;
>> +       const struct samsung_cpuclk_soc_data *data = NULL;
>> +
>> +       if (np) {
>> +               match = of_match_node(samsung_clock_ids_armclk, np);
>> +               data = match ? match->data : NULL;
>> +       }
>
>
> Since this is rather Exynos-specific and Exynos is DT-only, np being NULL
> would be simply an error.

The cpu clock type is usable for not-dt samsung platform also.

>
> Best regards,
> Tomasz

Thanks for your review.

Regards,
Thomas.

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-12 14:58     ` Tomasz Figa
@ 2014-02-13  8:02       ` Thomas Abraham
  -1 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-13  8:02 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: cpufreq, linux-arm-kernel, linux-samsung-soc, Mike Turquette,
	Shawn Guo, Kukjin Kim, Lukasz Majewski, Viresh Kumar, thomas.ab,
	Heiko Stübner, Rafael J. Wysocki

On Wed, Feb 12, 2014 at 8:28 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Thomas,
>
>
> On 07.02.2014 16:55, Thomas Abraham wrote:
>>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> Lookup for the optional boost-frequency property in cpu0 node and if
>> available, enable support for boost mode frequencies. The frequencies
>> usable in boost mode are determined while preparing the cpufreq table
>> from the list of operating points available.
>>
>> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
>> this driver by default. On platforms that do not support boost mode,
>> the boost mode frequencies will not be specified in cpu0 node and
>> hence the boost mode support will not be enabled. Since this driver
>> anyways depends on THERMAL config option, it is safe to enable
>> CPU_FREQ_BOOST_SW config option as default.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Cc: Lukasz Majewski <l.majewski@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>   Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>>   drivers/cpufreq/Kconfig                                    |    1 +
>>   drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>>   3 files changed, 6 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..60f321a 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,8 @@ Optional properties:
>>   - cooling-min-level:
>>   - cooling-max-level:
>>        Please refer to
>> Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- boost-frequency:
>> +     Please refer to
>> Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>>
>>   Examples:
>>
>> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>> index 4b029c0..52cc704 100644
>> --- a/drivers/cpufreq/Kconfig
>> +++ b/drivers/cpufreq/Kconfig
>> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>>         tristate "Generic CPU0 cpufreq driver"
>>         depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>>         select PM_OPP
>> +       select CPU_FREQ_BOOST_SW
>>         help
>>           This adds a generic cpufreq driver for CPU0 frequency
>> management.
>>           It supports both uniprocessor (UP) and symmetric multiprocessor
>> (SMP)
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
>> b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..06539eb 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device
>> *pdev)
>>                         transition_latency += ret * 1000;
>>         }
>>
>> +       if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>> +               cpu0_cpufreq_driver.boost_supported = true;
>> +
>>         ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>>         if (ret) {
>>                 pr_err("failed register driver: %d\n", ret);
>>
>
> I'd say that boost should be enabled depending on user's preference, as done
> before in Exynos cpufreq driver. So both presence of boost-frequency
> property and state of CPU_FREQ_BOOST_SW should be considered.
>
> As for CPU_FREQ_BOOST_SW, I don't think it should be always selected, but
> ather, either converted to a user-selectable bool entry or made selectable
> by other entry, like current ARM_EXYNOS_CPU_FREQ_BOOST_SW.

We still will have the same problem on Exynos multi-platform kernel
where one Exynos platform needs it and others don't. Same with just
using the CPU_FREQ_BOOST_SW config option. So that was the reason to
just fallback on presence of boost property.

Thanks,
Thomas.


>
> Best regards,
> Tomasz

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-13  8:02       ` Thomas Abraham
  0 siblings, 0 replies; 43+ messages in thread
From: Thomas Abraham @ 2014-02-13  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 12, 2014 at 8:28 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Thomas,
>
>
> On 07.02.2014 16:55, Thomas Abraham wrote:
>>
>> From: Thomas Abraham <thomas.ab@samsung.com>
>>
>> Lookup for the optional boost-frequency property in cpu0 node and if
>> available, enable support for boost mode frequencies. The frequencies
>> usable in boost mode are determined while preparing the cpufreq table
>> from the list of operating points available.
>>
>> In addition to this, enable the CPU_FREQ_BOOST_SW config option for
>> this driver by default. On platforms that do not support boost mode,
>> the boost mode frequencies will not be specified in cpu0 node and
>> hence the boost mode support will not be enabled. Since this driver
>> anyways depends on THERMAL config option, it is safe to enable
>> CPU_FREQ_BOOST_SW config option as default.
>>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Cc: Lukasz Majewski <l.majewski@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> ---
>>   Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt |    2 ++
>>   drivers/cpufreq/Kconfig                                    |    1 +
>>   drivers/cpufreq/cpufreq-cpu0.c                             |    3 +++
>>   3 files changed, 6 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> index f055515..60f321a 100644
>> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
>> @@ -19,6 +19,8 @@ Optional properties:
>>   - cooling-min-level:
>>   - cooling-max-level:
>>        Please refer to
>> Documentation/devicetree/bindings/thermal/thermal.txt.
>> +- boost-frequency:
>> +     Please refer to
>> Documentation/devicetree/bindings/cpufreq/cpufreq-boost.txt
>>
>>   Examples:
>>
>> diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
>> index 4b029c0..52cc704 100644
>> --- a/drivers/cpufreq/Kconfig
>> +++ b/drivers/cpufreq/Kconfig
>> @@ -187,6 +187,7 @@ config GENERIC_CPUFREQ_CPU0
>>         tristate "Generic CPU0 cpufreq driver"
>>         depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
>>         select PM_OPP
>> +       select CPU_FREQ_BOOST_SW
>>         help
>>           This adds a generic cpufreq driver for CPU0 frequency
>> management.
>>           It supports both uniprocessor (UP) and symmetric multiprocessor
>> (SMP)
>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
>> b/drivers/cpufreq/cpufreq-cpu0.c
>> index 0c12ffc..06539eb 100644
>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device
>> *pdev)
>>                         transition_latency += ret * 1000;
>>         }
>>
>> +       if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>> +               cpu0_cpufreq_driver.boost_supported = true;
>> +
>>         ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>>         if (ret) {
>>                 pr_err("failed register driver: %d\n", ret);
>>
>
> I'd say that boost should be enabled depending on user's preference, as done
> before in Exynos cpufreq driver. So both presence of boost-frequency
> property and state of CPU_FREQ_BOOST_SW should be considered.
>
> As for CPU_FREQ_BOOST_SW, I don't think it should be always selected, but
> ather, either converted to a user-selectable bool entry or made selectable
> by other entry, like current ARM_EXYNOS_CPU_FREQ_BOOST_SW.

We still will have the same problem on Exynos multi-platform kernel
where one Exynos platform needs it and others don't. Same with just
using the CPU_FREQ_BOOST_SW config option. So that was the reason to
just fallback on presence of boost property.

Thanks,
Thomas.


>
> Best regards,
> Tomasz

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

* Re: [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
  2014-02-13  8:02       ` Thomas Abraham
@ 2014-02-13 11:08         ` Tomasz Figa
  -1 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-13 11:08 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: cpufreq, linux-arm-kernel, linux-samsung-soc, Mike Turquette,
	Shawn Guo, Kukjin Kim, Lukasz Majewski, Viresh Kumar, thomas.ab,
	Heiko Stübner, Rafael J. Wysocki

On 13.02.2014 09:02, Thomas Abraham wrote:
> On Wed, Feb 12, 2014 at 8:28 PM, Tomasz Figa <t.figa@samsung.com> wrote:
>> Hi Thomas,
>>
>>
>> On 07.02.2014 16:55, Thomas Abraham wrote:

[snip]

>>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
>>> b/drivers/cpufreq/cpufreq-cpu0.c
>>> index 0c12ffc..06539eb 100644
>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device
>>> *pdev)
>>>                          transition_latency += ret * 1000;
>>>          }
>>>
>>> +       if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>>> +               cpu0_cpufreq_driver.boost_supported = true;
>>> +
>>>          ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>>>          if (ret) {
>>>                  pr_err("failed register driver: %d\n", ret);
>>>
>>
>> I'd say that boost should be enabled depending on user's preference, as done
>> before in Exynos cpufreq driver. So both presence of boost-frequency
>> property and state of CPU_FREQ_BOOST_SW should be considered.
>>
>> As for CPU_FREQ_BOOST_SW, I don't think it should be always selected, but
>> ather, either converted to a user-selectable bool entry or made selectable
>> by other entry, like current ARM_EXYNOS_CPU_FREQ_BOOST_SW.
>
> We still will have the same problem on Exynos multi-platform kernel
> where one Exynos platform needs it and others don't. Same with just
> using the CPU_FREQ_BOOST_SW config option. So that was the reason to
> just fallback on presence of boost property.

I don't think we really have a problem here, because we have well 
defined semantics for particular enable methods:

  - Kconfig is supposed to be a global enable - if an option is 
disabled, it is not even built into the kernel and can be used in any 
way - this is per-user choice, regardless of platform the image is going 
to be running on,

  - device tree is supposed to be telling us whether the hardware we are 
running on supports given feature and all the required data to enable 
it, if yes,

  - then, for per system configuration, you should be able to 
enable/disable given feature by a command line parameter, e.g. 
cpufreq.boost_disable.

If you follow the above description, you should be able to get any 
configuration you want on any system, as long as it's supported by hardware.

Best regards,
Tomasz

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

* [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies
@ 2014-02-13 11:08         ` Tomasz Figa
  0 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-13 11:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 13.02.2014 09:02, Thomas Abraham wrote:
> On Wed, Feb 12, 2014 at 8:28 PM, Tomasz Figa <t.figa@samsung.com> wrote:
>> Hi Thomas,
>>
>>
>> On 07.02.2014 16:55, Thomas Abraham wrote:

[snip]

>>> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
>>> b/drivers/cpufreq/cpufreq-cpu0.c
>>> index 0c12ffc..06539eb 100644
>>> --- a/drivers/cpufreq/cpufreq-cpu0.c
>>> +++ b/drivers/cpufreq/cpufreq-cpu0.c
>>> @@ -195,6 +195,9 @@ static int cpu0_cpufreq_probe(struct platform_device
>>> *pdev)
>>>                          transition_latency += ret * 1000;
>>>          }
>>>
>>> +       if (of_find_property(cpu_dev->of_node, "boost-frequency", NULL))
>>> +               cpu0_cpufreq_driver.boost_supported = true;
>>> +
>>>          ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
>>>          if (ret) {
>>>                  pr_err("failed register driver: %d\n", ret);
>>>
>>
>> I'd say that boost should be enabled depending on user's preference, as done
>> before in Exynos cpufreq driver. So both presence of boost-frequency
>> property and state of CPU_FREQ_BOOST_SW should be considered.
>>
>> As for CPU_FREQ_BOOST_SW, I don't think it should be always selected, but
>> ather, either converted to a user-selectable bool entry or made selectable
>> by other entry, like current ARM_EXYNOS_CPU_FREQ_BOOST_SW.
>
> We still will have the same problem on Exynos multi-platform kernel
> where one Exynos platform needs it and others don't. Same with just
> using the CPU_FREQ_BOOST_SW config option. So that was the reason to
> just fallback on presence of boost property.

I don't think we really have a problem here, because we have well 
defined semantics for particular enable methods:

  - Kconfig is supposed to be a global enable - if an option is 
disabled, it is not even built into the kernel and can be used in any 
way - this is per-user choice, regardless of platform the image is going 
to be running on,

  - device tree is supposed to be telling us whether the hardware we are 
running on supports given feature and all the required data to enable 
it, if yes,

  - then, for per system configuration, you should be able to 
enable/disable given feature by a command line parameter, e.g. 
cpufreq.boost_disable.

If you follow the above description, you should be able to get any 
configuration you want on any system, as long as it's supported by hardware.

Best regards,
Tomasz

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

* Re: [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
  2014-02-13  7:58       ` Thomas Abraham
@ 2014-02-13 14:31         ` Tomasz Figa
  -1 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-13 14:31 UTC (permalink / raw)
  To: Thomas Abraham
  Cc: cpufreq, linux-arm-kernel, linux-samsung-soc, Mike Turquette,
	Shawn Guo, Kukjin Kim, Lukasz Majewski, Viresh Kumar, thomas.ab,
	Heiko Stübner

On 13.02.2014 08:58, Thomas Abraham wrote:
> On Wed, Feb 12, 2014 at 11:55 PM, Tomasz Figa <t.figa@samsung.com> wrote:
>> On 07.02.2014 16:55, Thomas Abraham wrote:
>>> +/* common round rate callback useable for all types of cpu clocks */
>>> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
>>> +                       unsigned long drate, unsigned long *prate)
>>> +{
>>> +       struct clk *parent = __clk_get_parent(hw->clk);
>>> +       unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
>>> +       unsigned long t_prate, best_div = 1;
>>> +       unsigned long delta, min_delta = UINT_MAX;
>>> +
>>> +       do {
>>> +               t_prate = __clk_round_rate(parent, drate * best_div);
>>> +               delta = drate - (t_prate / best_div);
>>> +               if (delta < min_delta) {
>>> +                       *prate = t_prate;
>>> +                       min_delta = delta;
>>> +               }
>>> +               if (!delta)
>>> +                       break;
>>> +               best_div++;
>>> +       } while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
>>> +
>>> +       return t_prate / best_div;
>>> +}
>>
>>
>> I think there is something wrong with the code above. You increment best_div
>> in every iteration of the loop and use it to calculate the final best
>> frequency. Shouldn't best_div be the divisor which was found to give the
>> least delta and so the loop should rather iterate on a different variable
>> and store best_div only if (delta < min_delta) condition is true?
>
> This function finds out the best parent frequency (APLL in this case)
> which when divided with some divider value provides the the closest
> possible drate. Probably, the name best_div is misleading since there
> is no need to know the value of best_div outside this function.
>

What I mean is that the .round_rate() method is defined with two output 
values - best parent rate (*prate) and resulting rate of the clock 
itself (the value returned). Now, your function uses different divisor 
value to calculate the return value than the one found to give best 
delta, which is wrong.

>>
>> Anyway, I wonder if you couldn't somehow reuse the code from
>> drivers/clk/clk-divider.c...
>
> Yes, there are some similarities between these but they are not
> entirely the same.

They are implemented using slightly different ways (the one in 
clk-divider is more generic), but I believe they calculate exactly the same.

>>
>>
>>> +
>>> +static unsigned long _calc_div(unsigned long prate, unsigned long drate)
>>> +{
>>> +       unsigned long div = prate / drate;
>>> +
>>> +       WARN_ON(div >= MAX_DIV);
>>> +       return (!(prate % drate)) ? div-- : div;
>>> +}
>>> +
>>> +/* helper function to register a cpu clock */
>>> +static int __init samsung_cpuclk_register(unsigned int lookup_id,
>>
>>
>> Isn't the name a bit too generic? I'd say it should be
>> exynos_cpuclk_register(), since the implementation is rather Exynos specific
>> anyway.
>
> The implementation of the cpu clock type is supposed to be usable on
> all Samsung SoCs starting from s3c24xx onwards. I should have probably
> stated that explicitly.

I'm not sure how much of the code added by this patch could be reused by 
pre-Exynos platforms. AFAIK, except s5v210, their ARM frequency change 
semantics are completely different, so maybe we shouldn't bloat Exynos 
code by trying to make it too generic.

I believe we should keep this Exynos-specific right now to make the code 
simpler and, if needed and found to be appropriate after analyzing how 
cpufreq works on them, it might be extended to support older SoCs as 
well in future.

>>
>>
>>> +       init.parent_names = parents;
>>> +       init.num_parents = 1;
>>
>>
>> I believe this clock should take two clocks as its parents, because it can
>> dynamically switch between mout_apll and mout_mpll using mout_core mux.
>
> Since the mout_core mux is encapsulated into the cpu clock type, the
> dynamic switching is not allowed from CCF API. The switching is fully
> controlled by the cpu clock type when required and hence the CCF need
> not be told about 2 parents.
>

Semantically, the ARM clock can use two different parents, which are not 
encapsulated inside, but instead are fed into the ARM clock block from 
outside, so CCF should know about it.

However, looking at the clock core code again, it seems to support only 
num_parents > 1 when .get_parent() op is implemented, so for now it 
should be safe to keep it as is.

>>
>>
>>> +       init.ops = ops;
>>> +
>>> +       cpuclk->hw.init = &init;
>>> +       cpuclk->ctrl_base = base;
>>> +
>>> +       if (soc_data && soc_data->parser) {
>>
>>
>> Is it even possible to instantiate this clock without soc_data and parser
>> function? Shouldn't it simply bail out instead?
>
> Yes, the intent was to allow Samsung cpu clock type to usable on
> non-DT platforms as well. If a platform has soc_data, then the parser
> can be called.

If we keep this Exynos-specific, which I believe is better than making 
the code overly generic, this could be simplified.

>
>>
>>
>>> +               ret = soc_data->parser(np, &cpuclk->data);
>>> +               if (ret) {
>>> +                       pr_err("%s: error %d in parsing %s clock data",
>>> +                                       __func__, ret, name);
>>> +                       ret = -EINVAL;
>>> +                       goto free_cpuclk;
>>> +               }
>>> +               cpuclk->offset = soc_data->offset;
>>> +               init.ops = soc_data->ops;
>>> +       }
>>> +
>>> +       if (soc_data && soc_data->clk_cb) {
>>
>>
>> Same here. Does it make any sense to instantiate this clock without a
>> notifier callback?
>>
>>
>>> +               cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
>>> +               if (clk_notifier_register(__clk_lookup(parents[0]),
>>> +                               &cpuclk->clk_nb)) {
>>> +                       pr_err("%s: failed to register clock notifier for
>>> %s\n",
>>> +                                       __func__, name);
>>> +                       goto free_cpuclk_data;
>>> +               }
>>> +       }
>>> +
>>> +       if (num_parents == 2) {
>>
>>
>> When num_parents could be other than 2?
>
> If any Samsung SoC needs no alternate parent clock when changing armclk rate.
>

I don't see any real need for this for now. It can be added later if 
such need shows up. For now, I don't think much of this code will be 
reusable on pre-s5pv210 SoCs anyway and s5pv210 needs alternate parent 
too, so it's safe to support only such setup.

>>> +       if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
>>> +               div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
>>> +               div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
>>> +       }
>>> +
>>> +       /*
>>> +        * if the new and old parent clock speed is less than the clock
>>> speed
>>> +        * of the alternate parent, then it should be ensured that at no
>>> point
>>> +        * the armclk speed is more than the old_prate until the dividers
>>> are
>>> +        * set.
>>> +        */
>>> +       need_safe_freq = ndata->old_rate < alt_prate &&
>>> +                               ndata->new_rate < alt_prate;
>>
>>
>> Are you sure this condition is correct? The parent clock (PLL) alone doesn't
>> fully determine the rate of ARM clock, because you are also changing
>> div_core. So you can end up with PLL going down, while ARM clock going up,
>> because the divisors are significantly lowered.
>
> Interesting! I did not think about this. Will fix it.
>
>>
>> I think you should compare ARM clock rates here OR just remove div_core
>> configuration, keeping it as 0 (divide by 1) all the time, except when safe
>> frequency is active.
>
> I would like to keep have div_core configuration, since it gives more
> options for armclk, not just limited to PLL speeds.

Could this be added later as an extension? The original Exynos cpufreq 
doesn't seem to change these divisors and I'm not sure if we should be 
touching them. I'd rather keep the semantics of the old driver, at least 
for now.

>>
>> You seem to always perform the configuration in pre rate change notifier,
>> but original cpufreq code used to do it depending on whether the new
>> frequency is less than old or not, e.g.
>
> Yes, but with the clock notifier callback, we need not do it like below.

I don't think so. Your code always seem to do the transition in exactly 
the same order, regardless of transition direction. I assume that 
original driver contained such distinction, because of some hardware 
requirements and so such semantics should be preserved in new code.

This series is a refactor and should not introduce functional changes. 
Any semantic changes should be done as separate patches to make sure 
that no regressions are introduced.

>>
>> The property should be prefixed with "#" as other properties defining number
>> of cells.
>
> Isn't # a unnecessary requirement here. The old dt bindings used to
> have it and I am not sure in what way it helps. And this is a samsung
> specific property. Anyways, I do not have any particular preference on
> this.

Well, all such properties used to follow this convention, so I'm not 
sure why we should be changing this.

>>
>>> +       prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
>>> +       if (!prop)
>>> +               return -EINVAL;
>>> +       if (!prop->value)
>>> +               return -EINVAL;
>>> +       if ((prop->length / sizeof(u32)) % cells)
>>> +               return -EINVAL;
>>> +       row = ((prop->length / sizeof(u32)) / cells) + 1;
>>
>>
>> Why + 1? Also the variable could be named in a bit more meaningful way, e.g.
>> num_rows.
>
> +1 since this is a zero terminated table. Will change the variable name.
>

To make this more clear, I'd say you should simply add 1 when calling 
kzalloc() and not include sentinel row in nr_rows...

>>
>>
>>> +
>>> +       *data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
>>> +       if (!*data)
>>> +               ret = -ENOMEM;
>>> +       tdata = *data;
>>> +
>>> +       val = prop->value;
>>> +       for (; row > 1; row--, tdata++) {

...then you could iterate here to 0. However to make the code more 
readable I would simply rewrite this to:

	for (row = 0; row < nr_rows; ++row, ++tdata) {

>>> +/**
>>> + * samsung_register_arm_clock: register arm clock with ccf.
>>> + * @lookup_id: armclk clock output id for the clock controller.
>>> + * @parent: name of the parent clock for armclk.
>>> + * @base: base address of the clock controller from which armclk is
>>> generated.
>>> + * @np: device tree node pointer of the clock controller (optional).
>>> + * @ops: clock ops for this clock (optional)
>>> + */
>>> +int __init samsung_register_arm_clock(unsigned int lookup_id,
>>> +               const char **parent_names, unsigned int num_parents,
>>> +               void __iomem *base, struct device_node *np, struct clk_ops
>>> *ops)
>>> +{
>>> +       const struct of_device_id *match;
>>> +       const struct samsung_cpuclk_soc_data *data = NULL;
>>> +
>>> +       if (np) {
>>> +               match = of_match_node(samsung_clock_ids_armclk, np);
>>> +               data = match ? match->data : NULL;
>>> +       }
>>
>>
>> Since this is rather Exynos-specific and Exynos is DT-only, np being NULL
>> would be simply an error.
>
> The cpu clock type is usable for not-dt samsung platform also.

As I said, I would recommend keeping this simple to cover just Exynos 
SoCs for now. The design might also consider s5pv210, but it's going to 
be fully converted to DT as well, so it should be safe to make this code 
DT-only.

Best regards,
Tomasz

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

* [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks
@ 2014-02-13 14:31         ` Tomasz Figa
  0 siblings, 0 replies; 43+ messages in thread
From: Tomasz Figa @ 2014-02-13 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

On 13.02.2014 08:58, Thomas Abraham wrote:
> On Wed, Feb 12, 2014 at 11:55 PM, Tomasz Figa <t.figa@samsung.com> wrote:
>> On 07.02.2014 16:55, Thomas Abraham wrote:
>>> +/* common round rate callback useable for all types of cpu clocks */
>>> +static long samsung_cpuclk_round_rate(struct clk_hw *hw,
>>> +                       unsigned long drate, unsigned long *prate)
>>> +{
>>> +       struct clk *parent = __clk_get_parent(hw->clk);
>>> +       unsigned long max_prate = __clk_round_rate(parent, UINT_MAX);
>>> +       unsigned long t_prate, best_div = 1;
>>> +       unsigned long delta, min_delta = UINT_MAX;
>>> +
>>> +       do {
>>> +               t_prate = __clk_round_rate(parent, drate * best_div);
>>> +               delta = drate - (t_prate / best_div);
>>> +               if (delta < min_delta) {
>>> +                       *prate = t_prate;
>>> +                       min_delta = delta;
>>> +               }
>>> +               if (!delta)
>>> +                       break;
>>> +               best_div++;
>>> +       } while ((drate * best_div) < max_prate && best_div <= MAX_DIV);
>>> +
>>> +       return t_prate / best_div;
>>> +}
>>
>>
>> I think there is something wrong with the code above. You increment best_div
>> in every iteration of the loop and use it to calculate the final best
>> frequency. Shouldn't best_div be the divisor which was found to give the
>> least delta and so the loop should rather iterate on a different variable
>> and store best_div only if (delta < min_delta) condition is true?
>
> This function finds out the best parent frequency (APLL in this case)
> which when divided with some divider value provides the the closest
> possible drate. Probably, the name best_div is misleading since there
> is no need to know the value of best_div outside this function.
>

What I mean is that the .round_rate() method is defined with two output 
values - best parent rate (*prate) and resulting rate of the clock 
itself (the value returned). Now, your function uses different divisor 
value to calculate the return value than the one found to give best 
delta, which is wrong.

>>
>> Anyway, I wonder if you couldn't somehow reuse the code from
>> drivers/clk/clk-divider.c...
>
> Yes, there are some similarities between these but they are not
> entirely the same.

They are implemented using slightly different ways (the one in 
clk-divider is more generic), but I believe they calculate exactly the same.

>>
>>
>>> +
>>> +static unsigned long _calc_div(unsigned long prate, unsigned long drate)
>>> +{
>>> +       unsigned long div = prate / drate;
>>> +
>>> +       WARN_ON(div >= MAX_DIV);
>>> +       return (!(prate % drate)) ? div-- : div;
>>> +}
>>> +
>>> +/* helper function to register a cpu clock */
>>> +static int __init samsung_cpuclk_register(unsigned int lookup_id,
>>
>>
>> Isn't the name a bit too generic? I'd say it should be
>> exynos_cpuclk_register(), since the implementation is rather Exynos specific
>> anyway.
>
> The implementation of the cpu clock type is supposed to be usable on
> all Samsung SoCs starting from s3c24xx onwards. I should have probably
> stated that explicitly.

I'm not sure how much of the code added by this patch could be reused by 
pre-Exynos platforms. AFAIK, except s5v210, their ARM frequency change 
semantics are completely different, so maybe we shouldn't bloat Exynos 
code by trying to make it too generic.

I believe we should keep this Exynos-specific right now to make the code 
simpler and, if needed and found to be appropriate after analyzing how 
cpufreq works on them, it might be extended to support older SoCs as 
well in future.

>>
>>
>>> +       init.parent_names = parents;
>>> +       init.num_parents = 1;
>>
>>
>> I believe this clock should take two clocks as its parents, because it can
>> dynamically switch between mout_apll and mout_mpll using mout_core mux.
>
> Since the mout_core mux is encapsulated into the cpu clock type, the
> dynamic switching is not allowed from CCF API. The switching is fully
> controlled by the cpu clock type when required and hence the CCF need
> not be told about 2 parents.
>

Semantically, the ARM clock can use two different parents, which are not 
encapsulated inside, but instead are fed into the ARM clock block from 
outside, so CCF should know about it.

However, looking at the clock core code again, it seems to support only 
num_parents > 1 when .get_parent() op is implemented, so for now it 
should be safe to keep it as is.

>>
>>
>>> +       init.ops = ops;
>>> +
>>> +       cpuclk->hw.init = &init;
>>> +       cpuclk->ctrl_base = base;
>>> +
>>> +       if (soc_data && soc_data->parser) {
>>
>>
>> Is it even possible to instantiate this clock without soc_data and parser
>> function? Shouldn't it simply bail out instead?
>
> Yes, the intent was to allow Samsung cpu clock type to usable on
> non-DT platforms as well. If a platform has soc_data, then the parser
> can be called.

If we keep this Exynos-specific, which I believe is better than making 
the code overly generic, this could be simplified.

>
>>
>>
>>> +               ret = soc_data->parser(np, &cpuclk->data);
>>> +               if (ret) {
>>> +                       pr_err("%s: error %d in parsing %s clock data",
>>> +                                       __func__, ret, name);
>>> +                       ret = -EINVAL;
>>> +                       goto free_cpuclk;
>>> +               }
>>> +               cpuclk->offset = soc_data->offset;
>>> +               init.ops = soc_data->ops;
>>> +       }
>>> +
>>> +       if (soc_data && soc_data->clk_cb) {
>>
>>
>> Same here. Does it make any sense to instantiate this clock without a
>> notifier callback?
>>
>>
>>> +               cpuclk->clk_nb.notifier_call = soc_data->clk_cb;
>>> +               if (clk_notifier_register(__clk_lookup(parents[0]),
>>> +                               &cpuclk->clk_nb)) {
>>> +                       pr_err("%s: failed to register clock notifier for
>>> %s\n",
>>> +                                       __func__, name);
>>> +                       goto free_cpuclk_data;
>>> +               }
>>> +       }
>>> +
>>> +       if (num_parents == 2) {
>>
>>
>> When num_parents could be other than 2?
>
> If any Samsung SoC needs no alternate parent clock when changing armclk rate.
>

I don't see any real need for this for now. It can be added later if 
such need shows up. For now, I don't think much of this code will be 
reusable on pre-s5pv210 SoCs anyway and s5pv210 needs alternate parent 
too, so it's safe to support only such setup.

>>> +       if (readl(base + SRC_CPU) & EXYNOS4210_MUX_HPM_MASK) {
>>> +               div1 = readl(base + DIV_CPU1) & EXYNOS4210_DIV1_HPM_MASK;
>>> +               div1 |= ((armclk_data->div1) & ~EXYNOS4210_DIV1_HPM_MASK);
>>> +       }
>>> +
>>> +       /*
>>> +        * if the new and old parent clock speed is less than the clock
>>> speed
>>> +        * of the alternate parent, then it should be ensured that at no
>>> point
>>> +        * the armclk speed is more than the old_prate until the dividers
>>> are
>>> +        * set.
>>> +        */
>>> +       need_safe_freq = ndata->old_rate < alt_prate &&
>>> +                               ndata->new_rate < alt_prate;
>>
>>
>> Are you sure this condition is correct? The parent clock (PLL) alone doesn't
>> fully determine the rate of ARM clock, because you are also changing
>> div_core. So you can end up with PLL going down, while ARM clock going up,
>> because the divisors are significantly lowered.
>
> Interesting! I did not think about this. Will fix it.
>
>>
>> I think you should compare ARM clock rates here OR just remove div_core
>> configuration, keeping it as 0 (divide by 1) all the time, except when safe
>> frequency is active.
>
> I would like to keep have div_core configuration, since it gives more
> options for armclk, not just limited to PLL speeds.

Could this be added later as an extension? The original Exynos cpufreq 
doesn't seem to change these divisors and I'm not sure if we should be 
touching them. I'd rather keep the semantics of the old driver, at least 
for now.

>>
>> You seem to always perform the configuration in pre rate change notifier,
>> but original cpufreq code used to do it depending on whether the new
>> frequency is less than old or not, e.g.
>
> Yes, but with the clock notifier callback, we need not do it like below.

I don't think so. Your code always seem to do the transition in exactly 
the same order, regardless of transition direction. I assume that 
original driver contained such distinction, because of some hardware 
requirements and so such semantics should be preserved in new code.

This series is a refactor and should not introduce functional changes. 
Any semantic changes should be done as separate patches to make sure 
that no regressions are introduced.

>>
>> The property should be prefixed with "#" as other properties defining number
>> of cells.
>
> Isn't # a unnecessary requirement here. The old dt bindings used to
> have it and I am not sure in what way it helps. And this is a samsung
> specific property. Anyways, I do not have any particular preference on
> this.

Well, all such properties used to follow this convention, so I'm not 
sure why we should be changing this.

>>
>>> +       prop = of_find_property(np, "samsung,armclk-divider-table", NULL);
>>> +       if (!prop)
>>> +               return -EINVAL;
>>> +       if (!prop->value)
>>> +               return -EINVAL;
>>> +       if ((prop->length / sizeof(u32)) % cells)
>>> +               return -EINVAL;
>>> +       row = ((prop->length / sizeof(u32)) / cells) + 1;
>>
>>
>> Why + 1? Also the variable could be named in a bit more meaningful way, e.g.
>> num_rows.
>
> +1 since this is a zero terminated table. Will change the variable name.
>

To make this more clear, I'd say you should simply add 1 when calling 
kzalloc() and not include sentinel row in nr_rows...

>>
>>
>>> +
>>> +       *data = kzalloc(sizeof(*tdata) * row, GFP_KERNEL);
>>> +       if (!*data)
>>> +               ret = -ENOMEM;
>>> +       tdata = *data;
>>> +
>>> +       val = prop->value;
>>> +       for (; row > 1; row--, tdata++) {

...then you could iterate here to 0. However to make the code more 
readable I would simply rewrite this to:

	for (row = 0; row < nr_rows; ++row, ++tdata) {

>>> +/**
>>> + * samsung_register_arm_clock: register arm clock with ccf.
>>> + * @lookup_id: armclk clock output id for the clock controller.
>>> + * @parent: name of the parent clock for armclk.
>>> + * @base: base address of the clock controller from which armclk is
>>> generated.
>>> + * @np: device tree node pointer of the clock controller (optional).
>>> + * @ops: clock ops for this clock (optional)
>>> + */
>>> +int __init samsung_register_arm_clock(unsigned int lookup_id,
>>> +               const char **parent_names, unsigned int num_parents,
>>> +               void __iomem *base, struct device_node *np, struct clk_ops
>>> *ops)
>>> +{
>>> +       const struct of_device_id *match;
>>> +       const struct samsung_cpuclk_soc_data *data = NULL;
>>> +
>>> +       if (np) {
>>> +               match = of_match_node(samsung_clock_ids_armclk, np);
>>> +               data = match ? match->data : NULL;
>>> +       }
>>
>>
>> Since this is rather Exynos-specific and Exynos is DT-only, np being NULL
>> would be simply an error.
>
> The cpu clock type is usable for not-dt samsung platform also.

As I said, I would recommend keeping this simple to cover just Exynos 
SoCs for now. The design might also consider s5pv210, but it's going to 
be fully converted to DT as well, so it should be safe to make this code 
DT-only.

Best regards,
Tomasz

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

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

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-07 15:55 [PATCH v3 0/7] cpufreq: use cpufreq-cpu0 driver for exynos based platforms Thomas Abraham
2014-02-07 15:55 ` Thomas Abraham
2014-02-07 15:55 ` Thomas Abraham
2014-02-07 15:55 ` [PATCH v3 1/7] cpufreq: cpufreq-cpu0: allow use of optional boost mode frequencies Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham
2014-02-07 16:16   ` Nishanth Menon
2014-02-07 16:16     ` Nishanth Menon
2014-02-08  5:19     ` Thomas Abraham
2014-02-08  5:19       ` Thomas Abraham
2014-02-08 16:31       ` Nishanth Menon
2014-02-08 16:31         ` Nishanth Menon
2014-02-10  8:20   ` Lukasz Majewski
2014-02-10  8:20     ` Lukasz Majewski
2014-02-12 14:58   ` Tomasz Figa
2014-02-12 14:58     ` Tomasz Figa
2014-02-13  8:02     ` Thomas Abraham
2014-02-13  8:02       ` Thomas Abraham
2014-02-13 11:08       ` Tomasz Figa
2014-02-13 11:08         ` Tomasz Figa
2014-02-07 15:55 ` [PATCH v3 2/7] clk: samsung: add infrastructure to register cpu clocks Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham
2014-02-10  9:00   ` Lukasz Majewski
2014-02-10  9:00     ` Lukasz Majewski
2014-02-12 18:25   ` Tomasz Figa
2014-02-12 18:25     ` Tomasz Figa
2014-02-13  7:58     ` Thomas Abraham
2014-02-13  7:58       ` Thomas Abraham
2014-02-13 14:31       ` Tomasz Figa
2014-02-13 14:31         ` Tomasz Figa
2014-02-07 15:55 ` [PATCH v3 3/7] Documentation: devicetree: add cpu clock configuration data binding for Exynos4/5 Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham
2014-02-07 15:55 ` [PATCH v3 4/7] clk: exynos: use cpu-clock provider type to represent arm clock Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham
2014-02-07 15:55 ` [PATCH v3 5/7] ARM: dts: Exynos: add cpu nodes, opp and cpu clock configuration data Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham
2014-02-07 16:20   ` Sudeep Holla
2014-02-07 16:20     ` Sudeep Holla
2014-02-08  5:20     ` Thomas Abraham
2014-02-08  5:20       ` Thomas Abraham
2014-02-07 15:55 ` [PATCH v3 6/7] ARM: Exynos: switch to using generic cpufreq-cpu0 driver Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham
2014-02-07 15:55 ` [PATCH v3 7/7] cpufreq: exynos: remove all exynos specific cpufreq driver support Thomas Abraham
2014-02-07 15:55   ` Thomas Abraham

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.