From 8afc6b62808d35f1446e49147fdce21ae9e7d3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Pe=C4=8Dovnik?= Date: Wed, 3 Feb 2021 20:18:28 +0100 Subject: [PATCH] Add DVFS fixes to current branch and change to mainline u-boot (#2598) --- config/kernel/linux-mvebu64-current.config | 2 +- config/sources/families/mvebu64.conf | 4 +- ...l-armada-37xx-add-syscon-compatible-.patch | 40 +++++ ...7xx-Fix-setting-TBG-parent-for-load-.patch | 146 ++++++++++++++++++ ...-37xx-periph-remove-.set_parent-meth.patch | 73 +++++++++ ...7xx-Fix-the-AVS-value-for-loads-L0-a.patch | 93 +++++++++++ ...-37xx-periph-Fix-switching-CPU-freq-.patch | 64 ++++++++ ...-37xx-periph-Fix-workaround-for-swit.patch | 112 ++++++++++++++ ...7xx-Fix-driver-cleanup-when-registra.patch | 39 +++++ ...7xx-Fix-determining-base-CPU-frequen.patch | 44 ++++++ ...a-37xx-Remove-cur_frequency-variable.patch | 46 ++++++ ...req-armada-37xx-Fix-module-unloading.patch | 69 +++++++++ 12 files changed, 729 insertions(+), 3 deletions(-) create mode 100644 patch/kernel/mvebu64-current/0001-arm64-dts-marvell-armada-37xx-add-syscon-compatible-.patch create mode 100644 patch/kernel/mvebu64-current/0002-cpufreq-armada-37xx-Fix-setting-TBG-parent-for-load-.patch create mode 100644 patch/kernel/mvebu64-current/0003-clk-mvebu-armada-37xx-periph-remove-.set_parent-meth.patch create mode 100644 patch/kernel/mvebu64-current/0004-cpufreq-armada-37xx-Fix-the-AVS-value-for-loads-L0-a.patch create mode 100644 patch/kernel/mvebu64-current/0005-clk-mvebu-armada-37xx-periph-Fix-switching-CPU-freq-.patch create mode 100644 patch/kernel/mvebu64-current/0006-clk-mvebu-armada-37xx-periph-Fix-workaround-for-swit.patch create mode 100644 patch/kernel/mvebu64-current/0007-cpufreq-armada-37xx-Fix-driver-cleanup-when-registra.patch create mode 100644 patch/kernel/mvebu64-current/0008-cpufreq-armada-37xx-Fix-determining-base-CPU-frequen.patch create mode 100644 patch/kernel/mvebu64-current/0009-cpufreq-armada-37xx-Remove-cur_frequency-variable.patch create mode 100644 patch/kernel/mvebu64-current/0010-cpufreq-armada-37xx-Fix-module-unloading.patch diff --git a/config/kernel/linux-mvebu64-current.config b/config/kernel/linux-mvebu64-current.config index 8e291172df..8a9b838f7e 100644 --- a/config/kernel/linux-mvebu64-current.config +++ b/config/kernel/linux-mvebu64-current.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm64 5.10.9 Kernel Configuration +# Linux/arm64 5.10.12 Kernel Configuration # CONFIG_CC_VERSION_TEXT="aarch64-linux-gnu-gcc (GNU Toolchain for the A-profile Architecture 8.3-2019.03 (arm-rel-8.36)) 8.3.0" CONFIG_CC_IS_GCC=y diff --git a/config/sources/families/mvebu64.conf b/config/sources/families/mvebu64.conf index 3a66b0857d..6a883cb6d1 100644 --- a/config/sources/families/mvebu64.conf +++ b/config/sources/families/mvebu64.conf @@ -1,6 +1,6 @@ ARCH=arm64 -BOOTSOURCE='https://github.com/MarvellEmbeddedProcessors/u-boot-marvell.git' -BOOTBRANCH='branch:u-boot-2018.03-armada-18.12' +BOOTSOURCE='https://github.com/u-boot/u-boot' +BOOTBRANCH='branch:v2021.01' BOOTENV_FILE='mvebu64.txt' ATFSOURCE='https://github.com/MarvellEmbeddedProcessors/atf-marvell' ATFDIR='arm-trusted-firmware-espressobin' diff --git a/patch/kernel/mvebu64-current/0001-arm64-dts-marvell-armada-37xx-add-syscon-compatible-.patch b/patch/kernel/mvebu64-current/0001-arm64-dts-marvell-armada-37xx-add-syscon-compatible-.patch new file mode 100644 index 0000000000..4373310367 --- /dev/null +++ b/patch/kernel/mvebu64-current/0001-arm64-dts-marvell-armada-37xx-add-syscon-compatible-.patch @@ -0,0 +1,40 @@ +From ff4e9b1be3e48ed22f30145fbccfaa49c8e87d10 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Wed, 7 Oct 2020 21:35:20 +0200 +Subject: [PATCH 01/10] arm64: dts: marvell: armada-37xx: add syscon compatible + to NB clk node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add "syscon" compatible to the North Bridge clocks node to allow the +cpufreq driver to access these registers via syscon API. + +This is needed for a fix of cpufreq driver. + +Signed-off-by: Marek Behún +Fixes: e8d66e7927b2 ("arm64: dts: marvell: armada-37xx: add nodes...") +Cc: stable@vger.kernel.org +Cc: Gregory CLEMENT +Cc: Miquel Raynal +--- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +index d5b6c0a1c54a..a89e47d95eef 100644 +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -156,7 +156,8 @@ uart1: serial@12200 { + }; + + nb_periph_clk: nb-periph-clk@13000 { +- compatible = "marvell,armada-3700-periph-clock-nb"; ++ compatible = "marvell,armada-3700-periph-clock-nb", ++ "syscon"; + reg = <0x13000 0x100>; + clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, + <&tbg 3>, <&xtalclk>; +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0002-cpufreq-armada-37xx-Fix-setting-TBG-parent-for-load-.patch b/patch/kernel/mvebu64-current/0002-cpufreq-armada-37xx-Fix-setting-TBG-parent-for-load-.patch new file mode 100644 index 0000000000..22309a5869 --- /dev/null +++ b/patch/kernel/mvebu64-current/0002-cpufreq-armada-37xx-Fix-setting-TBG-parent-for-load-.patch @@ -0,0 +1,146 @@ +From a900d6500bd22863d7fea47a25aefa2c9faab0fe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Wed, 7 Oct 2020 21:35:21 +0200 +Subject: [PATCH 02/10] cpufreq: armada-37xx: Fix setting TBG parent for load + levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With CPU frequency determining software [1] we have discovered that +after this driver does one CPU frequency change, the base frequency of +the CPU is set to the frequency of TBG-A-P clock, instead of the TBG +that is parent to the CPU. + +This can be reproduced on EspressoBIN and Turris MOX: + cd /sys/devices/system/cpu/cpufreq/policy0 + echo powersave >scaling_governor + echo performance >scaling_governor + +Running the mhz tool before this driver is loaded reports 1000 MHz, and +after loading the driver and executing commands above the tool reports +800 MHz. + +The change of TBG clock selector is supposed to happen in function +armada37xx_cpufreq_dvfs_setup. Before the function returns, it does +this: + parent = clk_get_parent(clk); + clk_set_parent(clk, parent); + +The armada-37xx-periph clock driver has the .set_parent method +implemented correctly for this, so if the method was actually called, +this would work. But since the introduction of the common clock +framework in commit b2476490ef11 ("clk: introduce the common clock..."), +the clk_set_parent function checks whether the parent is actually +changing, and if the requested new parent is same as the old parent +(which is obviously the case for the code above), the .set_parent method +is not called at all. + +This patch fixes this issue by filling the correct TBG clock selector +directly in the armada37xx_cpufreq_dvfs_setup during the filling of +other registers at the same address. But the determination of CPU TBG +index cannot be done via the common clock framework, therefore we need +to access the North Bridge Peripheral Clock registers directly in this +driver. + +[1] https://github.com/wtarreau/mhz + +Signed-off-by: Marek Behún +Fixes: 92ce45fb875d ("cpufreq: Add DVFS support for Armada 37xx") +Cc: stable@vger.kernel.org +Cc: Gregory CLEMENT +Cc: Miquel Raynal +--- + drivers/cpufreq/armada-37xx-cpufreq.c | 35 ++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index b4af4094309b..b8dc6c849579 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -25,6 +25,10 @@ + + #include "cpufreq-dt.h" + ++/* Clk register set */ ++#define ARMADA_37XX_CLK_TBG_SEL 0 ++#define ARMADA_37XX_CLK_TBG_SEL_CPU_OFF 22 ++ + /* Power management in North Bridge register set */ + #define ARMADA_37XX_NB_L0L1 0x18 + #define ARMADA_37XX_NB_L2L3 0x1C +@@ -120,10 +124,15 @@ static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq) + * will be configured then the DVFS will be enabled. + */ + static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, +- struct clk *clk, u8 *divider) ++ struct regmap *clk_base, u8 *divider) + { ++ u32 cpu_tbg_sel; + int load_lvl; +- struct clk *parent; ++ ++ /* Determine to which TBG clock is CPU connected */ ++ regmap_read(clk_base, ARMADA_37XX_CLK_TBG_SEL, &cpu_tbg_sel); ++ cpu_tbg_sel >>= ARMADA_37XX_CLK_TBG_SEL_CPU_OFF; ++ cpu_tbg_sel &= ARMADA_37XX_NB_TBG_SEL_MASK; + + for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { + unsigned int reg, mask, val, offset = 0; +@@ -142,6 +151,11 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, + mask = (ARMADA_37XX_NB_CLK_SEL_MASK + << ARMADA_37XX_NB_CLK_SEL_OFF); + ++ /* Set TBG index, for all levels we use the same TBG */ ++ val = cpu_tbg_sel << ARMADA_37XX_NB_TBG_SEL_OFF; ++ mask = (ARMADA_37XX_NB_TBG_SEL_MASK ++ << ARMADA_37XX_NB_TBG_SEL_OFF); ++ + /* + * Set cpu divider based on the pre-computed array in + * order to have balanced step. +@@ -160,14 +174,6 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, + + regmap_update_bits(base, reg, mask, val); + } +- +- /* +- * Set cpu clock source, for all the level we keep the same +- * clock source that the one already configured. For this one +- * we need to use the clock framework +- */ +- parent = clk_get_parent(clk); +- clk_set_parent(clk, parent); + } + + /* +@@ -358,11 +364,16 @@ static int __init armada37xx_cpufreq_driver_init(void) + struct platform_device *pdev; + unsigned long freq; + unsigned int cur_frequency, base_frequency; +- struct regmap *nb_pm_base, *avs_base; ++ struct regmap *nb_clk_base, *nb_pm_base, *avs_base; + struct device *cpu_dev; + int load_lvl, ret; + struct clk *clk, *parent; + ++ nb_clk_base = ++ syscon_regmap_lookup_by_compatible("marvell,armada-3700-periph-clock-nb"); ++ if (IS_ERR(nb_clk_base)) ++ return -ENODEV; ++ + nb_pm_base = + syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm"); + +@@ -439,7 +450,7 @@ static int __init armada37xx_cpufreq_driver_init(void) + armada37xx_cpufreq_avs_configure(avs_base, dvfs); + armada37xx_cpufreq_avs_setup(avs_base, dvfs); + +- armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); ++ armada37xx_cpufreq_dvfs_setup(nb_pm_base, nb_clk_base, dvfs->divider); + clk_put(clk); + + for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0003-clk-mvebu-armada-37xx-periph-remove-.set_parent-meth.patch b/patch/kernel/mvebu64-current/0003-clk-mvebu-armada-37xx-periph-remove-.set_parent-meth.patch new file mode 100644 index 0000000000..09ac2a22c0 --- /dev/null +++ b/patch/kernel/mvebu64-current/0003-clk-mvebu-armada-37xx-periph-remove-.set_parent-meth.patch @@ -0,0 +1,73 @@ +From 18304427b4ca4b97c76759553ea64341ea8cd2eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Wed, 7 Oct 2020 21:35:22 +0200 +Subject: [PATCH 03/10] clk: mvebu: armada-37xx-periph: remove .set_parent + method for CPU PM clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove the .set_parent method in clk_pm_cpu_ops. + +This method was supposed to be needed by the armada-37xx-cpufreq driver, +but was never actually called due to wrong assumptions in the cpufreq +driver. After this was fixed in the cpufreq driver, this method is not +needed anymore. + +Signed-off-by: Marek Behún +Fixes: 2089dc33ea0e ("clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks") +Cc: Gregory CLEMENT +Cc: Miquel Raynal +--- + drivers/clk/mvebu/armada-37xx-periph.c | 28 -------------------------- + 1 file changed, 28 deletions(-) + +diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c +index f5746f9ea929..6507bd2c5f31 100644 +--- a/drivers/clk/mvebu/armada-37xx-periph.c ++++ b/drivers/clk/mvebu/armada-37xx-periph.c +@@ -440,33 +440,6 @@ static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) + return val; + } + +-static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index) +-{ +- struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); +- struct regmap *base = pm_cpu->nb_pm_base; +- int load_level; +- +- /* +- * We set the clock parent only if the DVFS is available but +- * not enabled. +- */ +- if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base)) +- return -EINVAL; +- +- /* Set the parent clock for all the load level */ +- for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { +- unsigned int reg, mask, val, +- offset = ARMADA_37XX_NB_TBG_SEL_OFF; +- +- armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); +- +- val = index << offset; +- mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset; +- regmap_update_bits(base, reg, mask, val); +- } +- return 0; +-} +- + static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +@@ -592,7 +565,6 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + + static const struct clk_ops clk_pm_cpu_ops = { + .get_parent = clk_pm_cpu_get_parent, +- .set_parent = clk_pm_cpu_set_parent, + .round_rate = clk_pm_cpu_round_rate, + .set_rate = clk_pm_cpu_set_rate, + .recalc_rate = clk_pm_cpu_recalc_rate, +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0004-cpufreq-armada-37xx-Fix-the-AVS-value-for-loads-L0-a.patch b/patch/kernel/mvebu64-current/0004-cpufreq-armada-37xx-Fix-the-AVS-value-for-loads-L0-a.patch new file mode 100644 index 0000000000..e3f4a6d8e5 --- /dev/null +++ b/patch/kernel/mvebu64-current/0004-cpufreq-armada-37xx-Fix-the-AVS-value-for-loads-L0-a.patch @@ -0,0 +1,93 @@ +From edbd075dec02474616bcd83540ac6e90a7822a1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 8 Oct 2020 18:01:05 +0200 +Subject: [PATCH 04/10] cpufreq: armada-37xx: Fix the AVS value for loads L0 + and L1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The original CPU voltage value for load L1 is too low for Armada-37xx SoC +when base CPU frequency is 1000 or 1200 MHz. It leads to instabilities +where CPU gets stuck soon after dynamic voltage scaling from load L1 to L0. + +Update the CPU voltage value for loads L0 and L1 accordingly when base +frequency is 1000 or 1200 MHz. The minimal value is updated from the +original 1.05V to 1.108V. + +This change fixes instability issues on 1 GHz variant of Espressobin and +Turris MOX. It is based on previous work from Victor Gu +for Espressobin kernel 4.4 [1]. Discussion about this issue is also at +armbian forum [2]. + +[1] - https://github.com/MarvellEmbeddedProcessors/linux-marvell/commit/dc33b62c90696afb6adc7dbcc4ebbd48bedec269 +[2] - https://forum.armbian.com/topic/10429-how-to-make-espressobin-v7-stable/ + +Signed-off-by: Pali Rohár +Fixes: 1c3528232f4b ("cpufreq: armada-37xx: Add AVS support") +Cc: stable@vger.kernel.org +--- + drivers/cpufreq/armada-37xx-cpufreq.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index b8dc6c849579..92e531f700f4 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -73,6 +73,7 @@ + #define LOAD_LEVEL_NR 4 + + #define MIN_VOLT_MV 1000 ++#define MIN_VOLT_MV_FOR_L0_L1_1GHZ 1108 + + /* AVS value for the corresponding voltage (in mV) */ + static int avs_map[] = { +@@ -208,6 +209,8 @@ static u32 armada_37xx_avs_val_match(int target_vm) + * - L2 & L3 voltage should be about 150mv smaller than L0 voltage. + * This function calculates L1 & L2 & L3 AVS values dynamically based + * on L0 voltage and fill all AVS values to the AVS value table. ++ * When base CPU frequency is 1000 or 1200 MHz then there is additional ++ * minimal avs value for load L0 and L1. + */ + static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, + struct armada_37xx_dvfs *dvfs) +@@ -239,6 +242,15 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, + for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) + dvfs->avs[load_level] = avs_min; + ++ /* ++ * Set the avs value for load L0 and L1 when base CPU frequency is 1000/1200 MHz, ++ * otherwise the CPU gets stuck when switching from load L1 to load L0 ++ */ ++ if (dvfs->cpu_freq_max >= 1000*1000*1000) { ++ avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L0_L1_1GHZ); ++ dvfs->avs[0] = dvfs->avs[1] = avs_min; ++ } ++ + return; + } + +@@ -258,6 +270,20 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base, + target_vm = avs_map[l0_vdd_min] - 150; + target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV; + dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm); ++ ++ /* ++ * Fix the avs value for load L0 and L1 when base CPU frequency is 1000/1200 MHz, ++ * otherwise the CPU gets stuck when switching from load L1 to load L0 ++ */ ++ if (dvfs->cpu_freq_max >= 1000*1000*1000) { ++ u32 avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L0_L1_1GHZ); ++ ++ if (dvfs->avs[0] < avs_min) ++ dvfs->avs[0] = avs_min; ++ ++ if (dvfs->avs[1] < avs_min) ++ dvfs->avs[1] = avs_min; ++ } + } + + static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0005-clk-mvebu-armada-37xx-periph-Fix-switching-CPU-freq-.patch b/patch/kernel/mvebu64-current/0005-clk-mvebu-armada-37xx-periph-Fix-switching-CPU-freq-.patch new file mode 100644 index 0000000000..6cccb5995a --- /dev/null +++ b/patch/kernel/mvebu64-current/0005-clk-mvebu-armada-37xx-periph-Fix-switching-CPU-freq-.patch @@ -0,0 +1,64 @@ +From 9084ec43ddf97da84add774bd3614ebef20c4c9e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Tue, 3 Nov 2020 12:10:36 +0100 +Subject: [PATCH 05/10] clk: mvebu: armada-37xx-periph: Fix switching CPU freq + from 250 Mhz to 1 GHz +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was observed that the workaround introduced by commit 61c40f35f5cd +("clk: mvebu: armada-37xx-periph: Fix switching CPU rate from 300Mhz to +1.2GHz") when base CPU frequency is 1.2 GHz is also required when base +CPU frequency is 1 GHz. Otherwise switching CPU frequency directly from +L2 (250 MHz) to L0 (1 GHz) causes a crash. + +When base CPU frequency is just 800 MHz no crashed were observed during +switch from L2 to L0. + +Signed-off-by: Pali Rohár +Fixes: 2089dc33ea0e ("clk: mvebu: armada-37xx-periph: add DVFS support for cpu clocks") +Cc: stable@vger.kernel.org # 61c40f35f5cd ("clk: mvebu: armada-37xx-periph: Fix switching CPU rate from 300Mhz to 1.2GHz") +--- + drivers/clk/mvebu/armada-37xx-periph.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c +index 6507bd2c5f31..b15e177bea7e 100644 +--- a/drivers/clk/mvebu/armada-37xx-periph.c ++++ b/drivers/clk/mvebu/armada-37xx-periph.c +@@ -487,8 +487,10 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + } + + /* +- * Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz +- * respectively) to L0 frequency (1.2 Ghz) requires a significant ++ * Workaround when base CPU frequnecy is 1000 or 1200 MHz ++ * ++ * Switching the CPU from the L2 or L3 frequencies (250/300 or 200 MHz ++ * respectively) to L0 frequency (1/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 +@@ -498,15 +500,15 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + * 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) ++ * 1. First switch from L2/L3 (200/250/300 MHz) to L1 (500/600 MHz) + * 2. Sleep 20ms for stabling VDD voltage +- * 3. Then switch from L1(600MHZ) to L0(1200Mhz). ++ * 3. Then switch from L1 (500/600 MHz) to L0 (1000/1200 MHz). + */ + static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base) + { + unsigned int cur_level; + +- if (rate != 1200 * 1000 * 1000) ++ if (rate < 1000 * 1000 * 1000) + return; + + regmap_read(base, ARMADA_37XX_NB_CPU_LOAD, &cur_level); +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0006-clk-mvebu-armada-37xx-periph-Fix-workaround-for-swit.patch b/patch/kernel/mvebu64-current/0006-clk-mvebu-armada-37xx-periph-Fix-workaround-for-swit.patch new file mode 100644 index 0000000000..fb0881131d --- /dev/null +++ b/patch/kernel/mvebu64-current/0006-clk-mvebu-armada-37xx-periph-Fix-workaround-for-swit.patch @@ -0,0 +1,112 @@ +From 21e93728fff921ff01aceee6c80d265b2fcb2939 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Wed, 14 Oct 2020 10:35:51 +0200 +Subject: [PATCH 06/10] clk: mvebu: armada-37xx-periph: Fix workaround for + switching from L1 to L0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When CPU frequency is at 250 MHz and set_rate() is called with 500 MHz (L1) +quickly followed by a call with 1 GHz (L0), the CPU does not necessarily +stay in L1 for at least 20ms as is required by Marvell errata. + +This situation happens frequently with the ondemand cpufreq governor and +can be also reproduced with userspace governor. In most cases it causes CPU +to crash. + +This change fixes the above issue and ensures that the CPU always stays in +L1 for at least 20ms when switching from any state to L0. + +Signed-off-by: Marek Behún +Signed-off-by: Pali Rohár +Fixes: 61c40f35f5cd ("clk: mvebu: armada-37xx-periph: Fix switching CPU rate from 300Mhz to 1.2GHz") +Cc: stable@vger.kernel.org +--- + drivers/clk/mvebu/armada-37xx-periph.c | 45 ++++++++++++++++++++++---- + 1 file changed, 39 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c +index b15e177bea7e..32ac6b6b7530 100644 +--- a/drivers/clk/mvebu/armada-37xx-periph.c ++++ b/drivers/clk/mvebu/armada-37xx-periph.c +@@ -84,6 +84,7 @@ struct clk_pm_cpu { + void __iomem *reg_div; + u8 shift_div; + struct regmap *nb_pm_base; ++ unsigned long l1_expiration; + }; + + #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) +@@ -504,22 +505,52 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + * 2. Sleep 20ms for stabling VDD voltage + * 3. Then switch from L1 (500/600 MHz) to L0 (1000/1200 MHz). + */ +-static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base) ++static void clk_pm_cpu_set_rate_wa(struct clk_pm_cpu *pm_cpu, ++ unsigned int new_level, unsigned long rate, ++ struct regmap *base) + { + unsigned int cur_level; + +- if (rate < 1000 * 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) ++ ++ if (cur_level == new_level) ++ return; ++ ++ /* ++ * System wants to go to L1 on its own. If we are going from L2/L3, ++ * remember when 20ms will expire. If from L0, set the value so that ++ * next switch to L0 won't have to wait. ++ */ ++ if (new_level == ARMADA_37XX_DVFS_LOAD_1) { ++ if (cur_level == ARMADA_37XX_DVFS_LOAD_0) ++ pm_cpu->l1_expiration = jiffies; ++ else ++ pm_cpu->l1_expiration = jiffies + msecs_to_jiffies(20); + return; ++ } ++ ++ /* ++ * If we are setting to L2/L3, just invalidate L1 expiration time, ++ * sleeping is not needed. ++ */ ++ if (rate < 1000*1000*1000) ++ goto invalidate_l1_exp; ++ ++ /* ++ * We are going to L0 with rate >= 1GHz. Check whether we have been at ++ * L1 for long enough time. If not, go to L1 for 20ms. ++ */ ++ if (pm_cpu->l1_expiration && jiffies >= pm_cpu->l1_expiration) ++ goto invalidate_l1_exp; + + regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD, + ARMADA_37XX_NB_CPU_LOAD_MASK, + ARMADA_37XX_DVFS_LOAD_1); + msleep(20); ++ ++invalidate_l1_exp: ++ pm_cpu->l1_expiration = 0; + } + + static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, +@@ -553,7 +584,9 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + reg = ARMADA_37XX_NB_CPU_LOAD; + mask = ARMADA_37XX_NB_CPU_LOAD_MASK; + +- clk_pm_cpu_set_rate_wa(rate, base); ++ /* Apply workaround when base CPU frequency is 1000 or 1200 MHz */ ++ if (parent_rate >= 1000*1000*1000) ++ clk_pm_cpu_set_rate_wa(pm_cpu, load_level, rate, base); + + regmap_update_bits(base, reg, mask, load_level); + +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0007-cpufreq-armada-37xx-Fix-driver-cleanup-when-registra.patch b/patch/kernel/mvebu64-current/0007-cpufreq-armada-37xx-Fix-driver-cleanup-when-registra.patch new file mode 100644 index 0000000000..35b398a4af --- /dev/null +++ b/patch/kernel/mvebu64-current/0007-cpufreq-armada-37xx-Fix-driver-cleanup-when-registra.patch @@ -0,0 +1,39 @@ +From 6facb50e286e10c42791512e17e8599f9f514d82 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Tue, 20 Oct 2020 16:37:45 +0200 +Subject: [PATCH 07/10] cpufreq: armada-37xx: Fix driver cleanup when + registration failed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 8db82563451f ("cpufreq: armada-37xx: fix frequency calculation for +opp") changed calculation of frequency passed to the dev_pm_opp_add() +function call. But the code for dev_pm_opp_remove() function call was not +updated, so the driver cleanup phase does not work when registration fails. + +This fixes the issue by using the same frequency in both calls. + +Signed-off-by: Pali Rohár +Fixes: 8db82563451f ("cpufreq: armada-37xx: fix frequency calculation for opp") +Cc: stable@vger.kernel.org +--- + drivers/cpufreq/armada-37xx-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index 92e531f700f4..002a71775e08 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -510,7 +510,7 @@ static int __init armada37xx_cpufreq_driver_init(void) + remove_opp: + /* clean-up the already added opp before leaving */ + while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) { +- freq = cur_frequency / dvfs->divider[load_lvl]; ++ freq = base_frequency / dvfs->divider[load_lvl]; + dev_pm_opp_remove(cpu_dev, freq); + } + +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0008-cpufreq-armada-37xx-Fix-determining-base-CPU-frequen.patch b/patch/kernel/mvebu64-current/0008-cpufreq-armada-37xx-Fix-determining-base-CPU-frequen.patch new file mode 100644 index 0000000000..7222c8e2a0 --- /dev/null +++ b/patch/kernel/mvebu64-current/0008-cpufreq-armada-37xx-Fix-determining-base-CPU-frequen.patch @@ -0,0 +1,44 @@ +From b7a63d67c67bfe3e807f634ac35aea6b09f7dc1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Tue, 20 Oct 2020 16:47:52 +0200 +Subject: [PATCH 08/10] cpufreq: armada-37xx: Fix determining base CPU + frequency +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When current CPU load is not L0 then loading armada-37xx-cpufreq.ko driver +fails with following error: + + # modprobe armada-37xx-cpufreq + [ 502.702097] Unsupported CPU frequency 250 MHz + +This issue was partially fixed by commit 8db82563451f ("cpufreq: +armada-37xx: fix frequency calculation for opp"), but only for calculating +CPU frequency for opp. + +Fix this also for determination of base CPU frequency. + +Signed-off-by: Pali Rohár +Fixes: 92ce45fb875d ("cpufreq: Add DVFS support for Armada 37xx") +Cc: stable@vger.kernel.org # 8db82563451f ("cpufreq: armada-37xx: fix frequency calculation for opp") +--- + drivers/cpufreq/armada-37xx-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index 002a71775e08..f08281fc525c 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -458,7 +458,7 @@ static int __init armada37xx_cpufreq_driver_init(void) + return -EINVAL; + } + +- dvfs = armada_37xx_cpu_freq_info_get(cur_frequency); ++ dvfs = armada_37xx_cpu_freq_info_get(base_frequency); + if (!dvfs) { + clk_put(clk); + return -EINVAL; +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0009-cpufreq-armada-37xx-Remove-cur_frequency-variable.patch b/patch/kernel/mvebu64-current/0009-cpufreq-armada-37xx-Remove-cur_frequency-variable.patch new file mode 100644 index 0000000000..4c7bab7e1a --- /dev/null +++ b/patch/kernel/mvebu64-current/0009-cpufreq-armada-37xx-Remove-cur_frequency-variable.patch @@ -0,0 +1,46 @@ +From f3274c42504e42a28a288c80f64309b4a915f9b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Tue, 20 Oct 2020 16:57:19 +0200 +Subject: [PATCH 09/10] cpufreq: armada-37xx: Remove cur_frequency variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Variable cur_frequency in armada37xx_cpufreq_driver_init() is unused. + +Signed-off-by: Pali Rohár +--- + drivers/cpufreq/armada-37xx-cpufreq.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index f08281fc525c..f13646d143de 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -389,7 +389,7 @@ static int __init armada37xx_cpufreq_driver_init(void) + struct armada_37xx_dvfs *dvfs; + struct platform_device *pdev; + unsigned long freq; +- unsigned int cur_frequency, base_frequency; ++ unsigned int base_frequency; + struct regmap *nb_clk_base, *nb_pm_base, *avs_base; + struct device *cpu_dev; + int load_lvl, ret; +@@ -450,14 +450,6 @@ static int __init armada37xx_cpufreq_driver_init(void) + return -EINVAL; + } + +- /* Get nominal (current) CPU frequency */ +- cur_frequency = clk_get_rate(clk); +- if (!cur_frequency) { +- dev_err(cpu_dev, "Failed to get clock rate for CPU\n"); +- clk_put(clk); +- return -EINVAL; +- } +- + dvfs = armada_37xx_cpu_freq_info_get(base_frequency); + if (!dvfs) { + clk_put(clk); +-- +2.25.1 + diff --git a/patch/kernel/mvebu64-current/0010-cpufreq-armada-37xx-Fix-module-unloading.patch b/patch/kernel/mvebu64-current/0010-cpufreq-armada-37xx-Fix-module-unloading.patch new file mode 100644 index 0000000000..eba0b42f96 --- /dev/null +++ b/patch/kernel/mvebu64-current/0010-cpufreq-armada-37xx-Fix-module-unloading.patch @@ -0,0 +1,69 @@ +From 1c2f3373daa919d624f6c28d0d3b024aec5bf55c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Tue, 20 Oct 2020 17:04:17 +0200 +Subject: [PATCH 10/10] cpufreq: armada-37xx: Fix module unloading +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This driver is missing module_exit hook. Add proper driver exit function +which unregisters the platform device and cleans up the data. + +Signed-off-by: Pali Rohár +--- + drivers/cpufreq/armada-37xx-cpufreq.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c +index f13646d143de..565c40f536ef 100644 +--- a/drivers/cpufreq/armada-37xx-cpufreq.c ++++ b/drivers/cpufreq/armada-37xx-cpufreq.c +@@ -85,6 +85,8 @@ static int avs_map[] = { + }; + + struct armada37xx_cpufreq_state { ++ struct platform_device *pdev; ++ struct device *cpu_dev; + struct regmap *regmap; + u32 nb_l0l1; + u32 nb_l2l3; +@@ -495,6 +497,9 @@ static int __init armada37xx_cpufreq_driver_init(void) + if (ret) + goto disable_dvfs; + ++ armada37xx_cpufreq_state->cpu_dev = cpu_dev; ++ armada37xx_cpufreq_state->pdev = pdev; ++ platform_set_drvdata(pdev, dvfs); + return 0; + + disable_dvfs: +@@ -513,6 +518,26 @@ static int __init armada37xx_cpufreq_driver_init(void) + /* late_initcall, to guarantee the driver is loaded after A37xx clock driver */ + late_initcall(armada37xx_cpufreq_driver_init); + ++static void __exit armada37xx_cpufreq_driver_exit(void) ++{ ++ struct platform_device *pdev = armada37xx_cpufreq_state->pdev; ++ struct armada_37xx_dvfs *dvfs = platform_get_drvdata(pdev); ++ unsigned long freq; ++ int load_lvl; ++ ++ platform_device_unregister(pdev); ++ ++ armada37xx_cpufreq_disable_dvfs(armada37xx_cpufreq_state->regmap); ++ ++ for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { ++ freq = dvfs->cpu_freq_max / dvfs->divider[load_lvl]; ++ dev_pm_opp_remove(armada37xx_cpufreq_state->cpu_dev, freq); ++ } ++ ++ kfree(armada37xx_cpufreq_state); ++} ++module_exit(armada37xx_cpufreq_driver_exit); ++ + static const struct of_device_id __maybe_unused armada37xx_cpufreq_of_match[] = { + { .compatible = "marvell,armada-3700-nb-pm" }, + { }, +-- +2.25.1 +