blob: 25a2020bd26e07e6742f40221705ff55fb577e27 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From f2b87dc1028b710ec8ce25808b9d21f92b376184 Mon Sep 17 00:00:00 2001
2From: Christian Lamparter <chunkeey@googlemail.com>
3Date: Sun, 11 Mar 2018 14:41:31 +0100
4Subject: [PATCH 2/2] clk: fix apss cpu overclocking
5
6There's an interaction issue between the clk changes:"
7clk: qcom: ipq4019: Add the apss cpu pll divider clock node
8clk: qcom: ipq4019: remove fixed clocks and add pll clocks
9" and the cpufreq-dt.
10
11cpufreq-dt is now spamming the kernel-log with the following:
12
13[ 1099.190658] cpu cpu0: dev_pm_opp_set_rate: failed to find current OPP
14for freq 761142857 (-34)
15
16This only happens on certain devices like the Compex WPJ428
17and AVM FritzBox!4040. However, other devices like the Asus
18RT-AC58U and Meraki MR33 work just fine.
19
20The issue stem from the fact that all higher CPU-Clocks
21are achieved by switching the clock-parent to the P_DDRPLLAPSS
22(ddrpllapss). Which is set by Qualcomm's proprietary bootcode
23as part of the DDR calibration.
24
25For example, the FB4040 uses 256 MiB Nanya NT5CC128M16IP clocked
26at round 533 MHz (ddrpllsdcc = 190285714 Hz).
27
28whereas the 128 MiB Nanya NT5CC64M16GP-DI in the ASUS RT-AC58U is
29clocked at a slightly higher 537 MHz ( ddrpllsdcc = 192000000 Hz).
30
31This patch attempts to fix the issue by modifying
32clk_cpu_div_round_rate(), clk_cpu_div_set_rate(), clk_cpu_div_recalc_rate()
33to use a new qcom_find_freq_close() function, which returns the closest
34matching frequency, instead of the next higher. This way, the SoC in
35the FB4040 (with its max clock speed of 710.4 MHz) will no longer
36try to overclock to 761 MHz.
37
38Fixes: d83dcacea18 ("clk: qcom: ipq4019: Add the apss cpu pll divider clock node")
39Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
40Signed-off-by: John Crispin <john@phrozen.org>
41---
42 drivers/clk/qcom/gcc-ipq4019.c | 34 +++++++++++++++++++++++++++++++---
43 1 file changed, 31 insertions(+), 3 deletions(-)
44
45--- a/drivers/clk/qcom/gcc-ipq4019.c
46+++ b/drivers/clk/qcom/gcc-ipq4019.c
47@@ -1243,6 +1243,29 @@ static const struct clk_fepll_vco gcc_fe
48 .reg = 0x2f020,
49 };
50
51+
52+const struct freq_tbl *qcom_find_freq_close(const struct freq_tbl *f,
53+ unsigned long rate)
54+{
55+ const struct freq_tbl *last = NULL;
56+
57+ for ( ; f->freq; f++) {
58+ if (rate == f->freq)
59+ return f;
60+
61+ if (f->freq > rate) {
62+ if (!last ||
63+ (f->freq - rate) < (rate - last->freq))
64+ return f;
65+ else
66+ return last;
67+ }
68+ last = f;
69+ }
70+
71+ return last;
72+}
73+
74 /*
75 * Round rate function for APSS CPU PLL Clock divider.
76 * It looks up the frequency table and returns the next higher frequency
77@@ -1255,7 +1278,7 @@ static long clk_cpu_div_round_rate(struc
78 struct clk_hw *p_hw;
79 const struct freq_tbl *f;
80
81- f = qcom_find_freq(pll->freq_tbl, rate);
82+ f = qcom_find_freq_close(pll->freq_tbl, rate);
83 if (!f)
84 return -EINVAL;
85
86@@ -1278,7 +1301,7 @@ static int clk_cpu_div_set_rate(struct c
87 u32 mask;
88 int ret;
89
90- f = qcom_find_freq(pll->freq_tbl, rate);
91+ f = qcom_find_freq_close(pll->freq_tbl, rate);
92 if (!f)
93 return -EINVAL;
94
95@@ -1305,6 +1328,7 @@ static unsigned long
96 clk_cpu_div_recalc_rate(struct clk_hw *hw,
97 unsigned long parent_rate)
98 {
99+ const struct freq_tbl *f;
100 struct clk_fepll *pll = to_clk_fepll(hw);
101 u32 cdiv, pre_div;
102 u64 rate;
103@@ -1325,7 +1349,11 @@ clk_cpu_div_recalc_rate(struct clk_hw *h
104 rate = clk_fepll_vco_calc_rate(pll, parent_rate) * 2;
105 do_div(rate, pre_div);
106
107- return rate;
108+ f = qcom_find_freq_close(pll->freq_tbl, rate);
109+ if (!f)
110+ return rate;
111+
112+ return f->freq;
113 };
114
115 static const struct clk_ops clk_regmap_cpu_div_ops = {