You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.3 KiB
93 lines
3.3 KiB
6 years ago
|
From 61c40f35f5cd6f67ccbd7319a1722eb78c815989 Mon Sep 17 00:00:00 2001
|
||
|
From: Gregory CLEMENT <gregory.clement@bootlin.com>
|
||
|
Date: Tue, 19 Jun 2018 14:34:45 +0200
|
||
|
Subject: [PATCH] clk: mvebu: armada-37xx-periph: Fix switching CPU rate from
|
||
|
300Mhz to 1.2GHz
|
||
|
|
||
|
Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz
|
||
|
respectively) to L0 frequency (1.2 Ghz) requires a significant amount
|
||
|
of time to let VDD stabilize to the appropriate voltage. This amount of
|
||
|
time is large enough that it cannot be covered by the hardware
|
||
|
countdown register. Due to this, the CPU might start operating at L0
|
||
|
before the voltage is stabilized, leading to CPU stalls.
|
||
|
|
||
|
To work around this problem, we prevent switching directly from the
|
||
|
L2/L3 frequencies to the L0 frequency, and instead switch to the L1
|
||
|
frequency in-between. The sequence therefore becomes:
|
||
|
|
||
|
1. First switch from L2/L3(200/300MHz) to L1(600MHZ)
|
||
|
2. Sleep 20ms for stabling VDD voltage
|
||
|
3. Then switch from L1(600MHZ) to L0(1200Mhz).
|
||
|
|
||
|
It is based on the work done by Ken Ma <make@marvell.com>
|
||
|
|
||
|
Cc: stable@vger.kernel.org
|
||
|
Fixes: 2089dc33ea0e ("clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks")
|
||
|
Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
|
||
|
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
|
||
|
---
|
||
|
drivers/clk/mvebu/armada-37xx-periph.c | 38 ++++++++++++++++++++++++++
|
||
|
1 file changed, 38 insertions(+)
|
||
|
|
||
|
--- a/drivers/clk/mvebu/armada-37xx-periph.c
|
||
|
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
|
||
|
@@ -35,6 +35,7 @@
|
||
|
#define CLK_SEL 0x10
|
||
|
#define CLK_DIS 0x14
|
||
|
|
||
|
+#define ARMADA_37XX_DVFS_LOAD_1 1
|
||
|
#define LOAD_LEVEL_NR 4
|
||
|
|
||
|
#define ARMADA_37XX_NB_L0L1 0x18
|
||
|
@@ -507,6 +508,40 @@ static long clk_pm_cpu_round_rate(struct
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz
|
||
|
+ * respectively) to L0 frequency (1.2 Ghz) requires a significant
|
||
|
+ * amount of time to let VDD stabilize to the appropriate
|
||
|
+ * voltage. This amount of time is large enough that it cannot be
|
||
|
+ * covered by the hardware countdown register. Due to this, the CPU
|
||
|
+ * might start operating at L0 before the voltage is stabilized,
|
||
|
+ * leading to CPU stalls.
|
||
|
+ *
|
||
|
+ * To work around this problem, we prevent switching directly from the
|
||
|
+ * L2/L3 frequencies to the L0 frequency, and instead switch to the L1
|
||
|
+ * frequency in-between. The sequence therefore becomes:
|
||
|
+ * 1. First switch from L2/L3(200/300MHz) to L1(600MHZ)
|
||
|
+ * 2. Sleep 20ms for stabling VDD voltage
|
||
|
+ * 3. Then switch from L1(600MHZ) to L0(1200Mhz).
|
||
|
+ */
|
||
|
+static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base)
|
||
|
+{
|
||
|
+ unsigned int cur_level;
|
||
|
+
|
||
|
+ if (rate != 1200 * 1000 * 1000)
|
||
|
+ return;
|
||
|
+
|
||
|
+ regmap_read(base, ARMADA_37XX_NB_CPU_LOAD, &cur_level);
|
||
|
+ cur_level &= ARMADA_37XX_NB_CPU_LOAD_MASK;
|
||
|
+ if (cur_level <= ARMADA_37XX_DVFS_LOAD_1)
|
||
|
+ return;
|
||
|
+
|
||
|
+ regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD,
|
||
|
+ ARMADA_37XX_NB_CPU_LOAD_MASK,
|
||
|
+ ARMADA_37XX_DVFS_LOAD_1);
|
||
|
+ msleep(20);
|
||
|
+}
|
||
|
+
|
||
|
static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||
|
unsigned long parent_rate)
|
||
|
{
|
||
|
@@ -537,6 +572,9 @@ static int clk_pm_cpu_set_rate(struct cl
|
||
|
*/
|
||
|
reg = ARMADA_37XX_NB_CPU_LOAD;
|
||
|
mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
|
||
|
+
|
||
|
+ clk_pm_cpu_set_rate_wa(rate, base);
|
||
|
+
|
||
|
regmap_update_bits(base, reg, mask, load_level);
|
||
|
|
||
|
return rate;
|