mvebu: Add basic support for WRT1900AC (v1) and Turris Omnia (pre 2019)
[librecmc/librecmc.git] / target / linux / mvebu / patches-4.14 / 510-clk-mvebu-armada-37xx-periph-Fix-switching-CPU-rate-.patch
1 From 61c40f35f5cd6f67ccbd7319a1722eb78c815989 Mon Sep 17 00:00:00 2001
2 From: Gregory CLEMENT <gregory.clement@bootlin.com>
3 Date: Tue, 19 Jun 2018 14:34:45 +0200
4 Subject: [PATCH] clk: mvebu: armada-37xx-periph: Fix switching CPU rate from
5  300Mhz to 1.2GHz
6
7 Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz
8 respectively) to L0 frequency (1.2 Ghz) requires a significant amount
9 of time to let VDD stabilize to the appropriate voltage. This amount of
10 time is large enough that it cannot be covered by the hardware
11 countdown register. Due to this, the CPU might start operating at L0
12 before the voltage is stabilized, leading to CPU stalls.
13
14 To work around this problem, we prevent switching directly from the
15 L2/L3 frequencies to the L0 frequency, and instead switch to the L1
16 frequency in-between. The sequence therefore becomes:
17
18 1. First switch from L2/L3(200/300MHz) to L1(600MHZ)
19 2. Sleep 20ms for stabling VDD voltage
20 3. Then switch from L1(600MHZ) to L0(1200Mhz).
21
22 It is based on the work done by Ken Ma <make@marvell.com>
23
24 Cc: stable@vger.kernel.org
25 Fixes: 2089dc33ea0e ("clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks")
26 Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
27 Signed-off-by: Stephen Boyd <sboyd@kernel.org>
28 ---
29  drivers/clk/mvebu/armada-37xx-periph.c | 38 ++++++++++++++++++++++++++
30  1 file changed, 38 insertions(+)
31
32 --- a/drivers/clk/mvebu/armada-37xx-periph.c
33 +++ b/drivers/clk/mvebu/armada-37xx-periph.c
34 @@ -35,6 +35,7 @@
35  #define CLK_SEL                0x10
36  #define CLK_DIS                0x14
37  
38 +#define  ARMADA_37XX_DVFS_LOAD_1 1
39  #define LOAD_LEVEL_NR  4
40  
41  #define ARMADA_37XX_NB_L0L1    0x18
42 @@ -507,6 +508,40 @@ static long clk_pm_cpu_round_rate(struct
43         return -EINVAL;
44  }
45  
46 +/*
47 + * Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz
48 + * respectively) to L0 frequency (1.2 Ghz) requires a significant
49 + * amount of time to let VDD stabilize to the appropriate
50 + * voltage. This amount of time is large enough that it cannot be
51 + * covered by the hardware countdown register. Due to this, the CPU
52 + * might start operating at L0 before the voltage is stabilized,
53 + * leading to CPU stalls.
54 + *
55 + * To work around this problem, we prevent switching directly from the
56 + * L2/L3 frequencies to the L0 frequency, and instead switch to the L1
57 + * frequency in-between. The sequence therefore becomes:
58 + * 1. First switch from L2/L3(200/300MHz) to L1(600MHZ)
59 + * 2. Sleep 20ms for stabling VDD voltage
60 + * 3. Then switch from L1(600MHZ) to L0(1200Mhz).
61 + */
62 +static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base)
63 +{
64 +       unsigned int cur_level;
65 +
66 +       if (rate != 1200 * 1000 * 1000)
67 +               return;
68 +
69 +       regmap_read(base, ARMADA_37XX_NB_CPU_LOAD, &cur_level);
70 +       cur_level &= ARMADA_37XX_NB_CPU_LOAD_MASK;
71 +       if (cur_level <= ARMADA_37XX_DVFS_LOAD_1)
72 +               return;
73 +
74 +       regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD,
75 +                          ARMADA_37XX_NB_CPU_LOAD_MASK,
76 +                          ARMADA_37XX_DVFS_LOAD_1);
77 +       msleep(20);
78 +}
79 +
80  static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
81                                unsigned long parent_rate)
82  {
83 @@ -537,6 +572,9 @@ static int clk_pm_cpu_set_rate(struct cl
84                          */
85                         reg = ARMADA_37XX_NB_CPU_LOAD;
86                         mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
87 +
88 +                       clk_pm_cpu_set_rate_wa(rate, base);
89 +
90                         regmap_update_bits(base, reg, mask, load_level);
91  
92                         return rate;