Skip to contentSkip to conversation

cpufreq support for Marvell Armada XP

PATCH Superseded Thomas Petazzoni 4 participants 21 messages Jul 4, 2014 – Jul 16, 2014

Subsystems (7)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover cpufreq support for Marvell Armada XP

Mike, Viresh, Rafael, Jason, Gregory, Andrew, Sebastian,

This series of commits adds cpufreq support for the Marvell Armada XP processor. Adding this support involves touching several different areas:

- The core clock framework, to add a new clk_set_rate() notifier. See below for the explanation. This should go through Mike Turquette's tree. This is PATCH 01/08.

- Addition of an Armada XP cpufreq driver. This should go through the cpufreq maintainers, Viresh Kumar and Rafael J. Wysocki. This is PATCH 02/08.

- Improvements to the existing Armada XP cpu-clock driver. This should also go through Mike Turquette's tree, probably thanks to a pull request to be sent by the mvebu platform maintainers. This is PATCH 03/08.

- Extension of the Marvell EBU PMSU code in arch/arm/mach-mvebu/ to implement a clock notifier needed for the dynamic frequency change procedure. This patch should go through the mvebu maintainers tree. This is PATCH 05/08. Note that this patch has a build dependency on PATCH 01/08, while all other patches don't have any other build dependency.

- Misc other small changes (defconfigs, Device Tree, SMP initialization code) that are specific to the mvebu platform, also to be handled by the mvebu maintainers. Those are patches 4, 6, 7 and 8.

The only tricky part in this series is the addition of the APPLY_RATE_CHANGE clock notifier. All the details about why a new clock notifier is needed are exposed in the commit log of the first patch, "clk: add an APPLY_RATE_CHANGE notifier event during clk_set_rate()". Please read carefully this commit log to understand the reasons for this proposed clock notifier.

Basically, the issue is that the procedure to change the CPU clock frequency involves touching registers managed by the CPU clock driver, but also registers from the PMSU which is used for a wide range of power management activities, and is therefore handled by platform specific code in mach-mvebu.

Jason, this patch series is based on 3.16-rc3, but it applies fine even with mvebu/fixes and mvebu/soc merged (which contain some PMSU changes), so I haven't based the patch series on those branches.

Thanks,

Thomas

Thomas Petazzoni (8):
clk: add an APPLY_RATE_CHANGE notifier event during clk_set_rate()
cpufreq: add driver for Armada XP
clk: mvebu: extend clk-cpu for dynamic frequency scaling
ARM: mvebu: ensure CPU clocks are enabled
ARM: mvebu: extend PMSU code to support dynamic frequency scaling
ARM: mvebu: update Armada XP DT for dynamic frequency scaling
ARM: mvebu: allow enabling of cpufreq on Armada XP
ARM: mvebu: update mvebu_v7_defconfig with cpufreq support

 .../devicetree/bindings/clock/mvebu-cpu-clock.txt  |   5 +-
 arch/arm/boot/dts/armada-xp.dtsi                   |   2 +-
 arch/arm/configs/mvebu_v7_defconfig                |   1 +
 arch/arm/mach-mvebu/Kconfig                        |   1 +
 arch/arm/mach-mvebu/platsmp.c                      |   1 +
 arch/arm/mach-mvebu/pmsu.c                         | 168 +++++++++++++++++++++
 drivers/clk/clk.c                                  |   3 +
 drivers/clk/mvebu/clk-cpu.c                        |  79 +++++++++-
 drivers/cpufreq/Kconfig.arm                        |   6 +
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/armadaxp-cpufreq.c                 | 112 ++++++++++++++
 include/linux/clk.h                                |   4 +
 12 files changed, 375 insertions(+), 8 deletions(-)
 create mode 100644 drivers/cpufreq/armadaxp-cpufreq.c
Signature · 1 line
2.0.0
#1 lore raw

PATCH 1/8 clk: add an APPLY_RATE_CHANGE notifier event during clk_set_rate()

The current clk_set_rate() logic allows notifiers to be notified of three different events:

* PRE_RATE_CHANGE: before the clock driver ->set_rate() function is called.
* ABORT_RATE_CHANGE: called if the rate change failed
* POST_RATE_CHANGE: called after the rate change has been successfully done, but after ->recalc_rate() has been called, and only if the rate of the clock has actually changed.

This commit adds an additional APPLY_RATE_CHANGE, which we require on Armada XP to implement dynamic frequency scaling of the CPU clocks. The problem is as follows.

On Armada XP, there are three hardware blocks involved in the dynamic frequency scaling of the CPU clocks:

- The CPU clocks hardware block itself, whose registers are already "managed" by drivers/clk/mvebu/clk-cpu.c (compatible string:
marvell,armada-xp-cpu-clock). The driver currently only supports changing the rate of the CPU clock when the clock is off (i.e before we boot the secondary CPUs).

- The PMU DFS registers, which are used to configure the target frequency for a dynamic rate change. Those registers are relatively well isolated from other PMU registers, so they can also be "managed" by the drivers/clk/mvebu/clk-cpu.c.

- The PMSU registers, which are used to actually trigger the dynamic frequency change procedure, which consists in programming a bunch of PMSU registers, entering the idle state on the CPU we want to change the frequency, and then again reprogram a bunch of PMSU registers.

The procedure to change the frequency is:

1/ Reset some clocks using the CPU clocks hardware block. 2/ Define the target frequency using the PMU DFS registers. 3/ Do the actual frequency change using the PMSU registers.

However, the PMSU registers are already "managed" by a driver in arch/arm/mach-mvebu/pmsu.c, and the code there is needed for a wide variety of power management activities: booting of secondary CPUs, CPU hotplug, cpuidle, cpufreq, and soon suspend/resume. The same registers in the PMSU are used for several of those activities.

So, what we need to do is to have steps (1) and (2) above done in the CPU clocks driver, and then step (3) done through a clk notifier.

However, the current POST_RATE_CHANGE notifier is called too late (after ->recalc_rate) and only if the rate has changed. So it works fine for a pure notification of a frequency change, but it doesn't work if the notified code is actually involved in the frequency change, which is exactly the case we have here. Until the sequence that uses the PMSU registers has been executed, the rate of the CPU clock has not changed.

In order to solve this problem, we propose to add an APPLY_RATE_CHANGE notifier event, which gets called right after ->set_rate(), but before ->recalc_rate(), and therefore regardless of whether there was an actualy frequency change or not.

---
 drivers/clk/clk.c   | 3 +++
 include/linux/clk.h | 4 ++++
 2 files changed, 7 insertions(+)
drivers/clk/clk.c +3 -0
index 8b73ede..afa559b 100644
@@ -1525,6 +1525,9 @@ static void clk_change_rate(struct clk *clk)
 	if (!skip_set_rate && clk->ops->set_rate)
 		clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate);
 
+	if (clk->notifier_count)
+		__clk_notify(clk, APPLY_RATE_CHANGE, old_rate, clk->new_rate);
+
 	clk->rate = clk_recalc(clk, best_parent_rate);
 
 	if (clk->notifier_count && old_rate != clk->rate)
include/linux/clk.h +4 -0
index fb5e097..9ea9f5f 100644
@@ -39,10 +39,14 @@ struct clk;
  * POST_RATE_CHANGE - called after the clk rate change has successfully
  *     completed.  Callbacks must always return NOTIFY_DONE or NOTIFY_OK.
  *
+ * APPLY_RATE_CHANGE - called right after calling ->set_rate(), but
+ *     before recalculating the rate.
+ *
  */
 #define PRE_RATE_CHANGE			BIT(0)
 #define POST_RATE_CHANGE		BIT(1)
 #define ABORT_RATE_CHANGE		BIT(2)
+#define APPLY_RATE_CHANGE		BIT(3)
 
 /**
  * struct clk_notifier - associate a clk with a notifier
Signature · 1 line
2.0.0
#2 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

In reply to Thomas Petazzoni

This commit adds a simple cpufreq driver for the Armada XP SoC, which has one separately controllable clock for each CPU. For this reason, the existing cpufreq-cpu0 generic driver cannot be used because it currently assumes that there is only one clock controlling the frequency of all CPUs.

There are on-going discussions on extending the cpufreq-cpu0 to cover the case of having one clock for each CPU, but there are still some unresolved issues to get this extended cpufreq-cpu0 driver merged. In the mean time, we propose to have an Armada XP specific cpufreq driver, and since the choice of the cpufreq driver does not affect the DT binding at all, it will always be time to get rid of this SoC-specific driver and use a more generic one when it becomes available.

In terms of implementation, this cpufreq driver supports two
frequencies: the nominal frequency of the CPU (which cannot be hardcoded, since it can be changed through Sample At Reset pins) and half of this frequency. The frequency change itself is implemented by simply calling clk_set_rate() on the appropriate CPU clock.

---
 drivers/cpufreq/Kconfig.arm        |   6 ++
 drivers/cpufreq/Makefile           |   1 +
 drivers/cpufreq/armadaxp-cpufreq.c | 112 +++++++++++++++++++++++++++++++++++++
 3 files changed, 119 insertions(+)
 create mode 100644 drivers/cpufreq/armadaxp-cpufreq.c
drivers/cpufreq/Kconfig.arm +6 -0
index ebac671..825b273 100644
@@ -24,6 +24,12 @@ config ARM_VEXPRESS_SPC_CPUFREQ
           This add the CPUfreq driver support for Versatile Express
 	  big.LITTLE platforms using SPC for power management.
 
+config ARM_ARMADAXP_CPUFREQ
+	bool "Marvell Armada XP"
+	depends on MACH_ARMADA_XP
+	default y
+	help
+	  This adds the CPUFreq driver for Marvell Armada XP SoC.
 
 config ARM_EXYNOS_CPUFREQ
 	bool
drivers/cpufreq/Makefile +1 -0
index 738c8b7..e260a0c 100644
@@ -49,6 +49,7 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
 # LITTLE drivers, so that it is probed last.
 obj-$(CONFIG_ARM_DT_BL_CPUFREQ)		+= arm_big_little_dt.o
 
+obj-$(CONFIG_ARM_ARMADAXP_CPUFREQ)	+= armadaxp-cpufreq.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
drivers/cpufreq/armadaxp-cpufreq.c new file +112 -0

112 lines not on this page · raw message

Signature · 1 line
2.0.0
maintainer
#3 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 9 lines · Thomas Petazzoni

This commit adds a simple cpufreq driver for the Armada XP SoC, which has one separately controllable clock for each CPU. For this reason, the existing cpufreq-cpu0 generic driver cannot be used because it currently assumes that there is only one clock controlling the frequency of all CPUs.

There are on-going discussions on extending the cpufreq-cpu0 to cover the case of having one clock for each CPU, but there are still some unresolved issues to get this extended cpufreq-cpu0 driver merged.

Exactly, and those changes would get merged in one form or the other. Surely in 3.17 atleast, if not 3.16 as we are already reaching rc4..

So, it would be great if you can test on top of those changes to see if something isn't solved for your platform yet?

git://git.linaro.org/people/viresh.kumar/linux.git cpufreq/cpu0-krait-v3

--
viresh

#4 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Dear Viresh Kumar,

Thanks for your feedback!

Quoted 12 lines · Viresh Kumar
Quoted 9 lines · Thomas Petazzoni

This commit adds a simple cpufreq driver for the Armada XP SoC, which has one separately controllable clock for each CPU. For this reason, the existing cpufreq-cpu0 generic driver cannot be used because it currently assumes that there is only one clock controlling the frequency of all CPUs.

There are on-going discussions on extending the cpufreq-cpu0 to cover the case of having one clock for each CPU, but there are still some unresolved issues to get this extended cpufreq-cpu0 driver merged.

Quoted 7 lines

Exactly, and those changes would get merged in one form or the other. Surely in 3.17 atleast, if not 3.16 as we are already reaching rc4..

So, it would be great if you can test on top of those changes to see if something isn't solved for your platform yet?

git://git.linaro.org/people/viresh.kumar/linux.git cpufreq/cpu0-krait-v3

One other problem with cpufreq-cpu0 is that it assumes the Device Tree can contain a static OPP table, with the frequency/voltage points. Unfortunately, in the case of the Armada XP platform, this is not possible, because we cannot hardcode into the Device Tree the possible CPU frequencies.

The nominal CPU frequency is selected by Sample on Reset pins (i.e pins of the CPUs that are sampled during the reset sequence) and can therefore change from one board to the other, and they can also be changed via special U-Boot commands. And the frequencies supported by cpufreq are the nominal frequency of the CPU as determined by the sample at reset pins, and half of this frequency.

That's why the proposed armadaxp-cpufreq driver does not hardcode the possible frequencies, but instead creates the frequency table by using the current CPU frequency (nominal frequency) and half of it.

This doesn't work very well with the idea of having the OPP table statically encoded in to the Device Tree. Options are:

- Improve the cpufreq-cpu0 driver so that the OPP table can be passed through platform_data, and therefore built dynamically by the platform code and passed when registering the cpufreq platform_device.

- Dynamically build/update the OPP table in the Device Tree.

Which option do you think is appropriate here?

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
maintainer
#5 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 11 lines

This doesn't work very well with the idea of having the OPP table statically encoded in to the Device Tree. Options are:

- Improve the cpufreq-cpu0 driver so that the OPP table can be passed through platform_data, and therefore built dynamically by the platform code and passed when registering the cpufreq platform_device.

- Dynamically build/update the OPP table in the Device Tree.

Which option do you think is appropriate here?

It should also be noted that that applies to many Marvell SoCs. Kirkwood and Dove are the same.

Andrew

#6 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

In reply to Thomas Petazzoni

Am Freitag, den 04.07.2014, 13:12 +0200 schrieb Thomas Petazzoni:
[...]

Quoted 9 lines

This doesn't work very well with the idea of having the OPP table statically encoded in to the Device Tree. Options are:

- Improve the cpufreq-cpu0 driver so that the OPP table can be passed through platform_data, and therefore built dynamically by the platform code and passed when registering the cpufreq platform_device.

- Dynamically build/update the OPP table in the Device Tree.

This sounds like the right thing to do. Ideally your bootloader would do this for you, so you don't have to encode those properties statically at all.

Barebox already has facilities to fixup any loaded device tree. Have a look at of_register_fixup() there.

Regards,
Lucas

Signature · 2 lines
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |
maintainer
#7 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 10 lines · Lucas Stach

Am Freitag, den 04.07.2014, 13:12 +0200 schrieb Thomas Petazzoni:
[...]

Quoted 8 lines

This doesn't work very well with the idea of having the OPP table statically encoded in to the Device Tree. Options are:

- Improve the cpufreq-cpu0 driver so that the OPP table can be passed through platform_data, and therefore built dynamically by the platform code and passed when registering the cpufreq platform_device.

Quoted 8 lines
Quoted 1 line

- Dynamically build/update the OPP table in the Device Tree.

This sounds like the right thing to do. Ideally your bootloader would do this for you, so you don't have to encode those properties statically at all.

Barebox already has facilities to fixup any loaded device tree. Have a look at of_register_fixup() there.

We are talking about legacy devices here, which have been in the field for years. There is very little chance of a boot loader upgrade. Appended DT is the norm for these devices, and modifying the DT would have to happen in kernel.

Andrew

maintainer
#8 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 4 lines · Andrew Lunn

We are talking about legacy devices here, which have been in the field for years. There is very little chance of a boot loader upgrade. Appended DT is the norm for these devices, and modifying the DT would have to happen in kernel.

FWIW, I should mention that we don't need to fix DT's at all in your case. Just add OPPs at runtime using dev_pm_opp_add() API from within kernel, maybe from your arch/arm/mach-* folder and cpufreq-cpu0 would be able to parse them.

--
viresh

#9 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

In reply to Viresh Kumar

Dear Viresh Kumar,

Quoted 12 lines · Viresh Kumar
Quoted 9 lines · Thomas Petazzoni

This commit adds a simple cpufreq driver for the Armada XP SoC, which has one separately controllable clock for each CPU. For this reason, the existing cpufreq-cpu0 generic driver cannot be used because it currently assumes that there is only one clock controlling the frequency of all CPUs.

There are on-going discussions on extending the cpufreq-cpu0 to cover the case of having one clock for each CPU, but there are still some unresolved issues to get this extended cpufreq-cpu0 driver merged.

Quoted 7 lines

Exactly, and those changes would get merged in one form or the other. Surely in 3.17 atleast, if not 3.16 as we are already reaching rc4..

So, it would be great if you can test on top of those changes to see if something isn't solved for your platform yet?

git://git.linaro.org/people/viresh.kumar/linux.git cpufreq/cpu0-krait-v3

Are these changes in linux-next ? The mvebu maintainer Jason Cooper has pulled the cpufreq support for Armada XP, so it will appear in linux-next tomorrow. It would be good of the cpufreq-generic driver improvements (to support one clock per CPU) were also part of linux-next so that we could test that the combination works as expected (of course, I did test locally, but I'd like to ensure it still works in linux-next).

Could you get your tree in linux-next, or get your patches merged by Rafael in his linux-next branch so that they will appear in linux-next ?

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
maintainer
#10 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 2 lines · Thomas Petazzoni

Could you get your tree in linux-next, or get your patches merged by Rafael in his linux-next branch so that they will appear in linux-next ?

They aren't in yet and Rafael haven't started pushing stuff for 3.16 yet. But it might be pushed sometime soon, no deadlines decided yet.

#11 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Dear Viresh Kumar,

Quoted 6 lines · Viresh Kumar
Quoted 2 lines · Thomas Petazzoni

Could you get your tree in linux-next, or get your patches merged by Rafael in his linux-next branch so that they will appear in linux-next ?

They aren't in yet and Rafael haven't started pushing stuff for 3.16 yet.

I guess you meant 3.17, right?

Quoted 1 line

But it might be pushed sometime soon, no deadlines decided yet.

Would be good to have this soon, since the 3.17 merge window is approaching. You asked me to use this cpufreq-generic driver instead of a custom cpufreq driver, and I did the work to do that. So now I clearly hope that cpufreq-generic will be merged in 3.17.

Thanks!

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
maintainer
#12 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 1 line · Thomas Petazzoni

I guess you meant 3.17, right?

Yeah, sorry.

Quoted 4 lines

Would be good to have this soon, since the 3.17 merge window is approaching. You asked me to use this cpufreq-generic driver instead of a custom cpufreq driver, and I did the work to do that. So now I clearly hope that cpufreq-generic will be merged in 3.17.

Yeah, I have already pinged Rafael few days back on this. He came back from holidays last week and this is what he told me:

Jul 11 19:58:34 <vireshk> rafael, when are you going to pick stuff for 3.17?
Jul 11 19:59:11 <rafael> vireshk: next week i suppose

Do you depend on this patch btw?

https://www.mail-archive.com/linux-kernel at vger.kernel.org/msg675398.html

Actually there had been some objections to comparing clocks this way and we *might* hold this off, unless the bindings are finalized. Will get all other patches merged though.

#13 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Dear Viresh Kumar,

Quoted 10 lines · Viresh Kumar
Quoted 4 lines

Would be good to have this soon, since the 3.17 merge window is approaching. You asked me to use this cpufreq-generic driver instead of a custom cpufreq driver, and I did the work to do that. So now I clearly hope that cpufreq-generic will be merged in 3.17.

Yeah, I have already pinged Rafael few days back on this. He came back from holidays last week and this is what he told me:

Jul 11 19:58:34 <vireshk> rafael, when are you going to pick stuff for 3.17?
Jul 11 19:59:11 <rafael> vireshk: next week i suppose

Ok.

Quoted 7 lines

Do you depend on this patch btw?

https://www.mail-archive.com/linux-kernel at vger.kernel.org/msg675398.html

Actually there had been some objections to comparing clocks this way and we *might* hold this off, unless the bindings are finalized. Will get all other patches merged though.

I'm not sure to fully understand what this patch is doing, but I believe I depend on it. My system has one clock for each CPU, and therefore each CPU has a separately controllable frequency. See
http://git.infradead.org/linux-mvebu.git/blob/3843607838cc5436d02a6771e661969a54c2fee0:/arch/arm/boot/dts/armada-xp-mv78460.dtsi#l30
for the Device Tree part describing the CPUs. So the existing cpufreq-cpu0 (as of 3.16) doesn't work because it assumes there is one single clock controlling the frequency.

Best regards,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
maintainer
#14 lore raw

PATCH 2/8 cpufreq: add driver for Armada XP

Quoted 2 lines · Thomas Petazzoni

I'm not sure to fully understand what this patch is doing, but I believe I depend on it.

Yes, you do. I have cc'd you to the other thread where this was in discussion.

--
viresh

#15 lore raw

PATCH 3/8 clk: mvebu: extend clk-cpu for dynamic frequency scaling

In reply to Thomas Petazzoni

This commit extends the existing clk-cpu driver used on Marvell Armada XP platforms to support the dynamic frequency scaling of the CPU clock. Non-dynamic frequency change was already supported (and used before secondary CPUs are started), but the dynamic frequency change requires a completely different procedure.

In order to achieve this, the clk_cpu_set_rate() function is reworked to handle two separate cases:

- The case where the clock is enabled, which is the new dynamic frequency change code, implemented in clk_cpu_on_set_rate(). This part will be used for cpufreq activities.

- The case where the clock is disabled, which is the existing frequency change code, moved in clk_cpu_off_set_rate(). This part is already used to set the clock frequency of the secondary CPUs before starting them.

In order to implement the dynamic frequency change function, we need to access the PMU DFS registers, which are outside the currently mapped "Clock Complex" registers, so a new area of registers is now mapped. This affects the Device Tree binding, but we are careful to do it in a backward-compatible way (by allowing the second pair of registers to be non-existent, and in this case, ensuring clk_cpu_on_set_rate() returns an error).

Note that technically speaking, the clk_cpu_on_set_rate() does not do the entire procedure needed to change the frequency dynamically, as it involves touching a number of PMSU registers. This is done through a clock notifier registered by the PMSU driver in followup commits.

---
 .../devicetree/bindings/clock/mvebu-cpu-clock.txt  |  5 +-
 drivers/clk/mvebu/clk-cpu.c                        | 79 ++++++++++++++++++++--
 2 files changed, 77 insertions(+), 7 deletions(-)
Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt +3 -2
index feb8301..99c2146 100644
@@ -3,14 +3,15 @@ Device Tree Clock bindings for cpu clock of Marvell EBU platforms
 Required properties:
 - compatible : shall be one of the following:
 	"marvell,armada-xp-cpu-clock" - cpu clocks for Armada XP
-- reg : Address and length of the clock complex register set
+- reg : Address and length of the clock complex register set, followed
+        by address and length of the PMU DFS registers
 - #clock-cells : should be set to 1.
 - clocks : shall be the input parent clock phandle for the clock.
 
 cpuclk: clock-complex at d0018700 {
 	#clock-cells = <1>;
 	compatible = "marvell,armada-xp-cpu-clock";
-	reg = <0xd0018700 0xA0>;
+	reg = <0xd0018700 0xA0>, <0x1c054 0x10>;
 	clocks = <&coreclk 1>;
 }
 
drivers/clk/mvebu/clk-cpu.c +74 -5

122 lines not on this page · raw message

Signature · 1 line
2.0.0
#16 lore raw

PATCH 4/8 ARM: mvebu: ensure CPU clocks are enabled

In reply to Thomas Petazzoni

In the Armada XP SMP support code, we are reading the clock frequency of the booting CPU, and use that to assign the same frequency to the other CPUs, and we do this while the clocks are disabled.

However, the CPU clocks are in fact never prepared/enabled, and to support cpufreq, we now have two code paths to change the frequency of the CPU clocks in the CPU clock driver: one when the clock is enabled (dynamic frequency scaling), one when the clock is disabled (adjusting the CPU frequency before starting the CPU). In order for this to work, the CPU clocks now have to be prepared and enabled after the initial synchronization of the clock frequencies is done, so that all future rate changes of the CPU clocks will trigger a dynamic frequency scaling transition.

---
 arch/arm/mach-mvebu/platsmp.c | 1 +
 1 file changed, 1 insertion(+)
arch/arm/mach-mvebu/platsmp.c +1 -0
index 88b976b3..4880b0f 100644
@@ -67,6 +67,7 @@ static void __init set_secondary_cpus_clock(void)
 		if (!cpu_clk)
 			return;
 		clk_set_rate(cpu_clk, rate);
+		clk_prepare_enable(cpu_clk);
 	}
 }
 
Signature · 1 line
2.0.0
#17 lore raw

PATCH 5/8 ARM: mvebu: extend PMSU code to support dynamic frequency scaling

In reply to Thomas Petazzoni

This commit adds the necessary code in the Marvell EBU PMSU driver to support dynamic frequency scaling. In essence, what this new code does is that it registers a clock notifier of the CPU clocks. The notifier function listens to the newly introduced APPLY_RATE_CHANGE event, and uses that to finalize the frequency transition by doing the part of the procedure that involves the PMSU.

---
 arch/arm/mach-mvebu/pmsu.c | 168 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)
arch/arm/mach-mvebu/pmsu.c +168 -0
index 53a55c8..a114e4a 100644
@@ -18,20 +18,25 @@
 
 #define pr_fmt(fmt) "mvebu-pmsu: " fmt
 
+#include <linux/clk.h>
 #include <linux/cpu_pm.h>
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/smp.h>
 #include <linux/resource.h>
+#include <linux/slab.h>
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
 #include "common.h"
+#include "armada-370-xp.h"
 
 static void __iomem *pmsu_mp_base;
 
@@ -57,6 +62,10 @@ static void __iomem *pmsu_mp_base;
 #define PMSU_STATUS_AND_MASK_IRQ_MASK		BIT(24)
 #define PMSU_STATUS_AND_MASK_FIQ_MASK		BIT(25)
 
+#define PMSU_EVENT_STATUS_AND_MASK(cpu)     ((cpu * 0x100) + 0x120)
+#define PMSU_EVENT_STATUS_AND_MASK_DFS_DONE        BIT(1)
+#define PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK   BIT(17)
+
 #define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124)
 
 /* PMSU fabric registers */
@@ -296,3 +305,162 @@ int __init armada_370_xp_cpu_pm_init(void)
 
 arch_initcall(armada_370_xp_cpu_pm_init);
 early_initcall(armada_370_xp_pmsu_init);
+
+static void armada_xp_cpufreq_clk_set_local(void *data)
+{
+	u32 reg;
+	u32 cpu = smp_processor_id();
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/* Prepare to enter idle */
+	reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
+	reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT |
+	       PMSU_STATUS_AND_MASK_IRQ_MASK     |
+	       PMSU_STATUS_AND_MASK_FIQ_MASK;
+	writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
+
+	/* Request the DFS transition */
+	reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(cpu));
+	reg |= PMSU_CONTROL_AND_CONFIG_DFS_REQ;
+	writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(cpu));
+
+	/* The fact of entering idle will trigger the DFS transition */
+	wfi();
+
+	/*
+	 * We're back from idle, the DFS transition has completed,
+	 * clear the idle wait indication.
+	 */
+	reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
+	reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT;
+	writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
+
+	local_irq_restore(flags);
+}
+
+struct armada_xp_cpufreq_notifier_block {
+	struct notifier_block nb;
+	int cpu;
+};
+
+static int armada_xp_cpufreq_clk_notify(struct notifier_block *self,
+					unsigned long action, void *data)
+{
+	struct armada_xp_cpufreq_notifier_block *nb =
+		container_of(self, struct armada_xp_cpufreq_notifier_block, nb);
+	unsigned long timeout;
+	int cpu = nb->cpu;
+	u32 reg;
+
+	if (action != APPLY_RATE_CHANGE)
+		return 0;
+
+	/* Clear any previous DFS DONE event */
+	reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+	reg &= ~PMSU_EVENT_STATUS_AND_MASK_DFS_DONE;
+	writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+
+	/* Mask the DFS done interrupt, since we are going to poll */
+	reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+	reg |= PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK;
+	writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+
+	/* Trigger the DFS on the appropriate CPU */
+	smp_call_function_single(get_logical_index(cpu),
+				 armada_xp_cpufreq_clk_set_local, NULL, false);
+
+	/* Poll until the DFS done event is generated */
+	timeout = jiffies + HZ;
+	while (time_before(jiffies, timeout)) {
+		reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+		if (reg & PMSU_EVENT_STATUS_AND_MASK_DFS_DONE)
+			break;
+		udelay(10);
+	}
+
+	/* Restore the DFS mask to its original state */
+	reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+	reg &= ~BIT(17);
+	writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(cpu));
+
+	return NOTIFY_DONE;
+}
+
+static int __init armada_xp_pmsu_cpufreq_init(void)
+{
+	struct device_node *np;
+	struct resource res;
+	int i, ret;
+
+	if (!of_machine_is_compatible("marvell,armadaxp"))
+		return 0;
+
+	/*
+	 * In order to have proper cpufreq handling, we need to ensure
+	 * that the Device Tree description of the CPU clock includes
+	 * the definition of the PMU DFS registers. If not, we do not
+	 * register the clock notifier and the cpufreq driver. This
+	 * piece of code is only for compatibility with old Device
+	 * Trees.
+	 */
+	np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock");
+	if (!np)
+		return 0;
+
+	ret = of_address_to_resource(np, 1, &res);
+	if (ret) {
+		pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n");
+		of_node_put(np);
+		return 0;
+	}
+
+	of_node_put(np);
+
+	for (i = 0; i < ARMADA_XP_MAX_CPUS; i++) {
+		struct clk *clk;
+		struct armada_xp_cpufreq_notifier_block *nbs;
+		struct device_node *np;
+		int ret;
+
+		np = of_get_cpu_node(i, NULL);
+		if (!np)
+			return -ENODEV;
+
+		clk = of_clk_get(np, 0);
+		if (!clk) {
+			pr_err("Cannot get clock for CPU %d\n", i);
+			of_node_put(np);
+			return -ENODEV;
+		}
+
+		nbs = kzalloc(sizeof(struct armada_xp_cpufreq_notifier_block),
+			      GFP_KERNEL);
+		if (!nbs) {
+			pr_err("Cannot allocate memory for cpufreq notifier\n");
+			clk_put(clk);
+			of_node_put(np);
+			return -ENOMEM;
+		}
+
+		nbs->nb.notifier_call = armada_xp_cpufreq_clk_notify;
+		nbs->cpu = i;
+
+		ret = clk_notifier_register(clk, &nbs->nb);
+		if (ret) {
+			pr_err("Cannot register clock notifier\n");
+			kfree(nbs);
+			clk_put(clk);
+			of_node_put(np);
+			return ret;
+		}
+
+		of_node_put(np);
+	}
+
+	platform_device_register_simple("armadaxp-cpufreq", -1, NULL, 0);
+	return 0;
+}
+
+arch_initcall(armada_xp_pmsu_cpufreq_init);
Signature · 1 line
2.0.0
#18 lore raw

PATCH 6/8 ARM: mvebu: update Armada XP DT for dynamic frequency scaling

In reply to Thomas Petazzoni

In order to support dynamic frequency scaling, the cpuclk Device Tree node needs to be updated to describe a second set of registers describing the PMU DFS registers.

---
 arch/arm/boot/dts/armada-xp.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/boot/dts/armada-xp.dtsi +1 -1
index 5902e83..bff9f6c 100644
@@ -99,7 +99,7 @@
 			cpuclk: clock-complex at 18700 {
 				#clock-cells = <1>;
 				compatible = "marvell,armada-xp-cpu-clock";
-				reg = <0x18700 0xA0>;
+				reg = <0x18700 0xA0>, <0x1c054 0x10>;
 				clocks = <&coreclk 1>;
 			};
 
Signature · 1 line
2.0.0
#19 lore raw

PATCH 7/8 ARM: mvebu: allow enabling of cpufreq on Armada XP

In reply to Thomas Petazzoni

Now that all the pieces to enable cpufreq on Armada XP are in place, we can make MACH_ARMADA_XP select ARCH_HAS_CPUFREQ to allow the usage of dynamic frequency scaling on this platform.

---
 arch/arm/mach-mvebu/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/mach-mvebu/Kconfig +1 -0
index b9bc599..1ff60ef 100644
@@ -66,6 +66,7 @@ config MACH_ARMADA_XP
 	select CPU_PJ4B
 	select MACH_MVEBU_V7
 	select PINCTRL_ARMADA_XP
+	select ARCH_HAS_CPUFREQ
 	help
 	  Say 'Y' here if you want your kernel to support boards based
 	  on the Marvell Armada XP SoC with device tree.
Signature · 1 line
2.0.0
#20 lore raw

PATCH 8/8 ARM: mvebu: update mvebu_v7_defconfig with cpufreq support

In reply to Thomas Petazzoni

Now that the Armada XP supports dynamic CPU frequency scaling, it makes sense to enable the cpufreq subsystem in mvebu_v7_defconfig. There's no need to explicitly enable the Armada XP specific driver because it has a 'default y' with a 'depends on MACH_ARMADA_XP' so it gets enabled automatically as soon as the cpufreq subsystem is enabled.

---
 arch/arm/configs/mvebu_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/configs/mvebu_v7_defconfig +1 -0
index b0bfefa..22b94ea 100644
@@ -29,6 +29,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_FREQ=y
 CONFIG_VFP=y
 CONFIG_NET=y
 CONFIG_INET=y
Signature · 1 line
2.0.0