b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From f2b87dc1028b710ec8ce25808b9d21f92b376184 Mon Sep 17 00:00:00 2001 |
| 2 | From: Christian Lamparter <chunkeey@googlemail.com> |
| 3 | Date: Sun, 11 Mar 2018 14:41:31 +0100 |
| 4 | Subject: [PATCH 2/2] clk: fix apss cpu overclocking |
| 5 | |
| 6 | There's an interaction issue between the clk changes:" |
| 7 | clk: qcom: ipq4019: Add the apss cpu pll divider clock node |
| 8 | clk: qcom: ipq4019: remove fixed clocks and add pll clocks |
| 9 | " and the cpufreq-dt. |
| 10 | |
| 11 | cpufreq-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 |
| 14 | for freq 761142857 (-34) |
| 15 | |
| 16 | This only happens on certain devices like the Compex WPJ428 |
| 17 | and AVM FritzBox!4040. However, other devices like the Asus |
| 18 | RT-AC58U and Meraki MR33 work just fine. |
| 19 | |
| 20 | The issue stem from the fact that all higher CPU-Clocks |
| 21 | are achieved by switching the clock-parent to the P_DDRPLLAPSS |
| 22 | (ddrpllapss). Which is set by Qualcomm's proprietary bootcode |
| 23 | as part of the DDR calibration. |
| 24 | |
| 25 | For example, the FB4040 uses 256 MiB Nanya NT5CC128M16IP clocked |
| 26 | at round 533 MHz (ddrpllsdcc = 190285714 Hz). |
| 27 | |
| 28 | whereas the 128 MiB Nanya NT5CC64M16GP-DI in the ASUS RT-AC58U is |
| 29 | clocked at a slightly higher 537 MHz ( ddrpllsdcc = 192000000 Hz). |
| 30 | |
| 31 | This patch attempts to fix the issue by modifying |
| 32 | clk_cpu_div_round_rate(), clk_cpu_div_set_rate(), clk_cpu_div_recalc_rate() |
| 33 | to use a new qcom_find_freq_close() function, which returns the closest |
| 34 | matching frequency, instead of the next higher. This way, the SoC in |
| 35 | the FB4040 (with its max clock speed of 710.4 MHz) will no longer |
| 36 | try to overclock to 761 MHz. |
| 37 | |
| 38 | Fixes: d83dcacea18 ("clk: qcom: ipq4019: Add the apss cpu pll divider clock node") |
| 39 | Signed-off-by: Christian Lamparter <chunkeey@gmail.com> |
| 40 | Signed-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 = { |