Blame view
drivers/cpufreq/imx6q-cpufreq.c
17.2 KB
1dd538f07 cpufreq: add imx6... |
1 |
/* |
90ff4d1c3 MLK-14747 driver:... |
2 3 |
* Copyright (C) 2013-2016 Freescale Semiconductor, Inc. * Copyright 2017 NXP. |
1dd538f07 cpufreq: add imx6... |
4 5 6 7 8 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ |
80d1382e9 MLK-9739 cpufreq:... |
9 |
#include <linux/busfreq-imx.h> |
1dd538f07 cpufreq: add imx6... |
10 |
#include <linux/clk.h> |
b494b48da cpufreq: imx6q-cp... |
11 |
#include <linux/cpu.h> |
1dd538f07 cpufreq: add imx6... |
12 |
#include <linux/cpufreq.h> |
1dd538f07 cpufreq: add imx6... |
13 14 |
#include <linux/err.h> #include <linux/module.h> |
90ee80a6f MLK-14301: Revert... |
15 |
#include <linux/slab.h> |
1dd538f07 cpufreq: add imx6... |
16 |
#include <linux/of.h> |
e4db1c743 PM / OPP: rename ... |
17 |
#include <linux/pm_opp.h> |
1dd538f07 cpufreq: add imx6... |
18 19 |
#include <linux/platform_device.h> #include <linux/regulator/consumer.h> |
62300a004 MLK-9693 cpufreq:... |
20 |
#include <linux/suspend.h> |
1dd538f07 cpufreq: add imx6... |
21 22 23 |
#define PU_SOC_VOLTAGE_NORMAL 1250000 #define PU_SOC_VOLTAGE_HIGH 1275000 |
1a4dd3071 MLK-11252-02 cpuf... |
24 25 |
#define DC_VOLTAGE_MIN 1300000 #define DC_VOLTAGE_MAX 1400000 |
1dd538f07 cpufreq: add imx6... |
26 |
#define FREQ_1P2_GHZ 1200000000 |
276fa4846 MLK-10271 cpufreq... |
27 |
#define FREQ_396_MHZ 396000 |
90ff4d1c3 MLK-14747 driver:... |
28 |
#define FREQ_528_MHZ 528000 |
40b06ddfa MLK-13096-02 cpuf... |
29 |
#define FREQ_198_MHZ 198000 |
460db6ced MLK-13014 ARM: im... |
30 |
#define FREQ_24_MHZ 24000 |
1dd538f07 cpufreq: add imx6... |
31 |
|
a7062855a MLK-13616 ARM: im... |
32 |
struct regulator *arm_reg; |
1dd538f07 cpufreq: add imx6... |
33 |
static struct regulator *pu_reg; |
a7062855a MLK-13616 ARM: im... |
34 |
struct regulator *soc_reg; |
1a4dd3071 MLK-11252-02 cpuf... |
35 |
static struct regulator *dc_reg; |
1dd538f07 cpufreq: add imx6... |
36 37 38 39 40 41 |
static struct clk *arm_clk; static struct clk *pll1_sys_clk; static struct clk *pll1_sw_clk; static struct clk *step_clk; static struct clk *pll2_pfd2_396m_clk; |
a35fc5a33 cpufreq: imx: upd... |
42 |
/* clk used by i.MX6UL */ |
ced7bc8de MLK-11343-02 cpuf... |
43 44 45 |
static struct clk *pll1_bypass; static struct clk *pll1_bypass_src; static struct clk *pll1; |
a35fc5a33 cpufreq: imx: upd... |
46 47 |
static struct clk *pll2_bus_clk; static struct clk *secondary_sel_clk; |
1dd538f07 cpufreq: add imx6... |
48 |
static struct device *cpu_dev; |
cc87b8a8e imx6q: free OPP t... |
49 |
static bool free_opp; |
1dd538f07 cpufreq: add imx6... |
50 51 |
static struct cpufreq_frequency_table *freq_table; static unsigned int transition_latency; |
62300a004 MLK-9693 cpufreq:... |
52 |
static struct mutex set_cpufreq_lock; |
b4573d1d6 cpufreq: imx6q: c... |
53 54 |
static u32 *imx6_soc_volt; static u32 soc_opp_count; |
6babbe05d MLK-12623-01 cpuf... |
55 |
static bool ignore_dc_reg; |
1d733f828 MLK-13133-02 cpuf... |
56 |
static bool low_power_run_support; |
b4573d1d6 cpufreq: imx6q: c... |
57 |
|
9c0ebcf78 cpufreq: Implemen... |
58 |
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) |
1dd538f07 cpufreq: add imx6... |
59 |
{ |
47d43ba73 PM / OPP: rename ... |
60 |
struct dev_pm_opp *opp; |
1dd538f07 cpufreq: add imx6... |
61 |
unsigned long freq_hz, volt, volt_old; |
d4019f0a9 cpufreq: move fre... |
62 |
unsigned int old_freq, new_freq; |
1dd538f07 cpufreq: add imx6... |
63 |
int ret; |
62300a004 MLK-9693 cpufreq:... |
64 |
mutex_lock(&set_cpufreq_lock); |
d4019f0a9 cpufreq: move fre... |
65 66 |
new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; |
f1e77d6f0 MLK-12868-01 cpuf... |
67 |
old_freq = policy->cur; |
1dd538f07 cpufreq: add imx6... |
68 |
|
460db6ced MLK-13014 ARM: im... |
69 70 71 |
/* * ON i.MX6ULL, the 24MHz setpoint is not seen by cpufreq * so we neet to prevent the cpufreq change frequency |
40b06ddfa MLK-13096-02 cpuf... |
72 |
* from 24MHz to 198Mhz directly. busfreq will handle this |
460db6ced MLK-13014 ARM: im... |
73 74 |
* when exit from low bus mode. */ |
40b06ddfa MLK-13096-02 cpuf... |
75 |
if (old_freq == FREQ_24_MHZ && new_freq == FREQ_198_MHZ) { |
460db6ced MLK-13014 ARM: im... |
76 77 78 |
mutex_unlock(&set_cpufreq_lock); return 0; }; |
1dd538f07 cpufreq: add imx6... |
79 |
rcu_read_lock(); |
5d4879cda PM / OPP: rename ... |
80 |
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); |
1dd538f07 cpufreq: add imx6... |
81 82 83 84 |
if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld ", freq_hz); |
62300a004 MLK-9693 cpufreq:... |
85 |
mutex_unlock(&set_cpufreq_lock); |
1dd538f07 cpufreq: add imx6... |
86 87 |
return PTR_ERR(opp); } |
5d4879cda PM / OPP: rename ... |
88 |
volt = dev_pm_opp_get_voltage(opp); |
1dd538f07 cpufreq: add imx6... |
89 90 91 92 93 |
rcu_read_unlock(); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV ", |
d4019f0a9 cpufreq: move fre... |
94 95 |
old_freq / 1000, volt_old / 1000, new_freq / 1000, volt / 1000); |
80d1382e9 MLK-9739 cpufreq:... |
96 97 98 99 |
/* * CPU freq is increasing, so need to ensure * that bus frequency is increased too. */ |
1d733f828 MLK-13133-02 cpuf... |
100 101 102 103 |
if (low_power_run_support) { if (old_freq == freq_table[0].frequency) request_bus_freq(BUS_FREQ_HIGH); } else if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ) { |
80d1382e9 MLK-9739 cpufreq:... |
104 |
request_bus_freq(BUS_FREQ_HIGH); |
1d733f828 MLK-13133-02 cpuf... |
105 |
} |
5a571c352 cpufreq: imx6q: c... |
106 |
|
1dd538f07 cpufreq: add imx6... |
107 |
/* scaling up? scale voltage before frequency */ |
d4019f0a9 cpufreq: move fre... |
108 |
if (new_freq > old_freq) { |
22d0628a2 cpufreq: imx6: re... |
109 110 111 112 113 |
if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddpu up: %d ", ret); |
62300a004 MLK-9693 cpufreq:... |
114 |
mutex_unlock(&set_cpufreq_lock); |
22d0628a2 cpufreq: imx6: re... |
115 116 |
return ret; } |
b4573d1d6 cpufreq: imx6q: c... |
117 118 119 120 121 |
} ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddsoc up: %d ", ret); |
62300a004 MLK-9693 cpufreq:... |
122 |
mutex_unlock(&set_cpufreq_lock); |
b4573d1d6 cpufreq: imx6q: c... |
123 124 |
return ret; } |
1dd538f07 cpufreq: add imx6... |
125 126 127 128 129 |
ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d ", ret); |
62300a004 MLK-9693 cpufreq:... |
130 |
mutex_unlock(&set_cpufreq_lock); |
d4019f0a9 cpufreq: move fre... |
131 |
return ret; |
1dd538f07 cpufreq: add imx6... |
132 |
} |
1dd538f07 cpufreq: add imx6... |
133 134 135 136 137 138 |
} /* * The setpoints are selected per PLL/PDF frequencies, so we need to * reprogram PLL for frequency scaling. The procedure of reprogramming * PLL1 is as below. |
a35fc5a33 cpufreq: imx: upd... |
139 140 141 |
* For i.MX6UL, it has a secondary clk mux, the cpu frequency change * flow is slightly different from other i.MX6 OSC. * The cpu frequeny change flow for i.MX6(except i.MX6UL) is as below: |
1dd538f07 cpufreq: add imx6... |
142 143 144 145 |
* - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it * - Disable pll2_pfd2_396m_clk */ |
c97fa8900 MLK-14624 cpufreq... |
146 147 |
if (of_machine_is_compatible("fsl,imx6ul") || of_machine_is_compatible("fsl,imx6ull")) { |
a35fc5a33 cpufreq: imx: upd... |
148 149 150 151 152 153 154 155 |
/* * When changing pll1_sw_clk's parent to pll1_sys_clk, * CPU may run at higher than 528MHz, this will lead to * the system unstable if the voltage is lower than the * voltage of 528MHz, so lower the CPU frequency to one * half before changing CPU frequency. */ clk_set_rate(arm_clk, (old_freq >> 1) * 1000); |
1dd538f07 cpufreq: add imx6... |
156 |
clk_set_parent(pll1_sw_clk, pll1_sys_clk); |
a35fc5a33 cpufreq: imx: upd... |
157 158 159 160 161 162 |
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) clk_set_parent(secondary_sel_clk, pll2_bus_clk); else clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk); clk_set_parent(step_clk, secondary_sel_clk); clk_set_parent(pll1_sw_clk, step_clk); |
6babbe05d MLK-12623-01 cpuf... |
163 164 165 166 |
if (freq_hz > clk_get_rate(pll2_bus_clk)) { clk_set_rate(pll1, new_freq * 1000); clk_set_parent(pll1_sw_clk, pll1_sys_clk); } |
a35fc5a33 cpufreq: imx: upd... |
167 168 169 170 |
} else { clk_set_parent(step_clk, pll2_pfd2_396m_clk); clk_set_parent(pll1_sw_clk, step_clk); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { |
560cb1bc0 MLK-14653 cpufreq... |
171 172 173 174 175 |
/* Ensure that pll1_bypass is set back to * pll1. We have to do this first so that the * change rate done to pll1_sys_clk done below * can propagate up to pll1. */ |
6019bf6b9 MLK-13843: Ensure... |
176 |
clk_set_parent(pll1_bypass, pll1); |
560cb1bc0 MLK-14653 cpufreq... |
177 |
clk_set_rate(pll1_sys_clk, new_freq * 1000); |
a35fc5a33 cpufreq: imx: upd... |
178 |
clk_set_parent(pll1_sw_clk, pll1_sys_clk); |
6019bf6b9 MLK-13843: Ensure... |
179 180 181 182 183 184 |
} else { /* * Need to ensure that PLL1 is bypassed and enabled * before ARM-PODF is set. */ clk_set_parent(pll1_bypass, pll1_bypass_src); |
a35fc5a33 cpufreq: imx: upd... |
185 |
} |
1dd538f07 cpufreq: add imx6... |
186 187 188 |
} /* Ensure the arm clock divider is what we expect */ |
d4019f0a9 cpufreq: move fre... |
189 |
ret = clk_set_rate(arm_clk, new_freq * 1000); |
1dd538f07 cpufreq: add imx6... |
190 191 192 193 |
if (ret) { dev_err(cpu_dev, "failed to set clock rate: %d ", ret); regulator_set_voltage_tol(arm_reg, volt_old, 0); |
62300a004 MLK-9693 cpufreq:... |
194 |
mutex_unlock(&set_cpufreq_lock); |
d4019f0a9 cpufreq: move fre... |
195 |
return ret; |
1dd538f07 cpufreq: add imx6... |
196 197 198 |
} /* scaling down? scale voltage after frequency */ |
d4019f0a9 cpufreq: move fre... |
199 |
if (new_freq < old_freq) { |
1dd538f07 cpufreq: add imx6... |
200 |
ret = regulator_set_voltage_tol(arm_reg, volt, 0); |
5a571c352 cpufreq: imx6q: c... |
201 |
if (ret) { |
1dd538f07 cpufreq: add imx6... |
202 203 204 |
dev_warn(cpu_dev, "failed to scale vddarm down: %d ", ret); |
5a571c352 cpufreq: imx6q: c... |
205 206 |
ret = 0; } |
b4573d1d6 cpufreq: imx6q: c... |
207 208 209 210 211 212 |
ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddsoc down: %d ", ret); ret = 0; } |
22d0628a2 cpufreq: imx6: re... |
213 214 215 216 217 218 219 |
if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddpu down: %d ", ret); ret = 0; } |
1dd538f07 cpufreq: add imx6... |
220 221 |
} } |
80d1382e9 MLK-9739 cpufreq:... |
222 223 224 225 |
/* * If CPU is dropped to the lowest level, release the need * for a high bus frequency. */ |
1d733f828 MLK-13133-02 cpuf... |
226 227 228 229 |
if (low_power_run_support) { if (new_freq == freq_table[0].frequency) release_bus_freq(BUS_FREQ_HIGH); } else if (old_freq > FREQ_396_MHZ && new_freq <= FREQ_396_MHZ) { |
80d1382e9 MLK-9739 cpufreq:... |
230 |
release_bus_freq(BUS_FREQ_HIGH); |
1d733f828 MLK-13133-02 cpuf... |
231 |
} |
1dd538f07 cpufreq: add imx6... |
232 |
|
62300a004 MLK-9693 cpufreq:... |
233 |
mutex_unlock(&set_cpufreq_lock); |
d4019f0a9 cpufreq: move fre... |
234 |
return 0; |
1dd538f07 cpufreq: add imx6... |
235 236 237 238 |
} static int imx6q_cpufreq_init(struct cpufreq_policy *policy) { |
ef9f0601c MLK-9777 cpufreq:... |
239 |
int ret; |
652ed95d5 cpufreq: introduc... |
240 |
policy->clk = arm_clk; |
ef9f0601c MLK-9777 cpufreq:... |
241 242 243 244 245 246 247 248 |
policy->cur = clk_get_rate(arm_clk) / 1000; ret = cpufreq_generic_init(policy, freq_table, transition_latency); if (ret) { dev_err(cpu_dev, "imx6 cpufreq init failed! "); return ret; } |
1d733f828 MLK-13133-02 cpuf... |
249 |
if (low_power_run_support && policy->cur > freq_table[0].frequency) { |
ef9f0601c MLK-9777 cpufreq:... |
250 |
request_bus_freq(BUS_FREQ_HIGH); |
1d733f828 MLK-13133-02 cpuf... |
251 252 253 |
} else if (policy->cur > FREQ_396_MHZ) { request_bus_freq(BUS_FREQ_HIGH); } |
ef9f0601c MLK-9777 cpufreq:... |
254 |
return 0; |
1dd538f07 cpufreq: add imx6... |
255 |
} |
1dd538f07 cpufreq: add imx6... |
256 |
static struct cpufreq_driver imx6q_cpufreq_driver = { |
ae6b42713 cpufreq: Mark ARM... |
257 |
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, |
4f6ba385e cpufreq: imx6q: U... |
258 |
.verify = cpufreq_generic_frequency_table_verify, |
9c0ebcf78 cpufreq: Implemen... |
259 |
.target_index = imx6q_set_target, |
652ed95d5 cpufreq: introduc... |
260 |
.get = cpufreq_generic_get, |
1dd538f07 cpufreq: add imx6... |
261 |
.init = imx6q_cpufreq_init, |
1dd538f07 cpufreq: add imx6... |
262 |
.name = "imx6q-cpufreq", |
4f6ba385e cpufreq: imx6q: U... |
263 |
.attr = cpufreq_generic_attr, |
1dd538f07 cpufreq: add imx6... |
264 |
}; |
62300a004 MLK-9693 cpufreq:... |
265 266 267 268 269 270 271 272 273 274 275 276 277 |
static int imx6_cpufreq_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) { struct cpufreq_policy *data = cpufreq_cpu_get(0); static u32 cpufreq_policy_min_pre_suspend; /* * During suspend/resume, When cpufreq driver try to increase * voltage/freq, it needs to control I2C/SPI to communicate * with external PMIC to adjust voltage, but these I2C/SPI * devices may be already suspended, to avoid such scenario, * we just increase cpufreq to highest setpoint before suspend. */ |
39bf6af34 MLK-11912 cpufreq... |
278 279 |
if (!data) return NOTIFY_BAD; |
62300a004 MLK-9693 cpufreq:... |
280 281 282 283 |
switch (event) { case PM_SUSPEND_PREPARE: cpufreq_policy_min_pre_suspend = data->user_policy.min; data->user_policy.min = data->user_policy.max; |
1a4dd3071 MLK-11252-02 cpuf... |
284 |
|
6babbe05d MLK-12623-01 cpuf... |
285 |
if (!IS_ERR(dc_reg) && !ignore_dc_reg) |
1a4dd3071 MLK-11252-02 cpuf... |
286 |
regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MAX, 0); |
62300a004 MLK-9693 cpufreq:... |
287 288 289 |
break; case PM_POST_SUSPEND: data->user_policy.min = cpufreq_policy_min_pre_suspend; |
1a4dd3071 MLK-11252-02 cpuf... |
290 |
|
6babbe05d MLK-12623-01 cpuf... |
291 |
if (!IS_ERR(dc_reg) && !ignore_dc_reg) |
1a4dd3071 MLK-11252-02 cpuf... |
292 |
regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0); |
62300a004 MLK-9693 cpufreq:... |
293 294 295 296 297 298 |
break; default: break; } cpufreq_update_policy(0); |
afcf68ffd MLK-12328 cpufreq... |
299 |
cpufreq_cpu_put(data); |
62300a004 MLK-9693 cpufreq:... |
300 301 302 303 304 305 306 |
return NOTIFY_OK; } static struct notifier_block imx6_cpufreq_pm_notifier = { .notifier_call = imx6_cpufreq_pm_notify, }; |
1dd538f07 cpufreq: add imx6... |
307 308 309 |
static int imx6q_cpufreq_probe(struct platform_device *pdev) { struct device_node *np; |
47d43ba73 PM / OPP: rename ... |
310 |
struct dev_pm_opp *opp; |
602a44634 MLK-13119-3 cpufr... |
311 |
struct clk *vpu_axi_podf; |
1dd538f07 cpufreq: add imx6... |
312 313 |
unsigned long min_volt, max_volt; int num, ret; |
b4573d1d6 cpufreq: imx6q: c... |
314 315 |
const struct property *prop; const __be32 *val; |
a3e09694d MLK-10123: cpufre... |
316 |
u32 nr, j, i = 0; |
602a44634 MLK-13119-3 cpufr... |
317 |
u32 vpu_axi_rate = 0; |
1dd538f07 cpufreq: add imx6... |
318 |
|
b494b48da cpufreq: imx6q-cp... |
319 320 321 322 323 324 |
cpu_dev = get_cpu_device(0); if (!cpu_dev) { pr_err("failed to get cpu0 device "); return -ENODEV; } |
1dd538f07 cpufreq: add imx6... |
325 |
|
cdc58d602 cpufreq: imx6q-cp... |
326 |
np = of_node_get(cpu_dev->of_node); |
1dd538f07 cpufreq: add imx6... |
327 328 329 330 331 |
if (!np) { dev_err(cpu_dev, "failed to find cpu0 node "); return -ENOENT; } |
90ee80a6f MLK-14301: Revert... |
332 333 334 335 336 337 338 339 |
arm_clk = clk_get(cpu_dev, "arm"); pll1_sys_clk = clk_get(cpu_dev, "pll1_sys"); pll1_sw_clk = clk_get(cpu_dev, "pll1_sw"); step_clk = clk_get(cpu_dev, "step"); pll2_pfd2_396m_clk = clk_get(cpu_dev, "pll2_pfd2_396m"); pll1 = clk_get(cpu_dev, "pll1"); pll1_bypass = clk_get(cpu_dev, "pll1_bypass"); pll1_bypass_src = clk_get(cpu_dev, "pll1_bypass_src"); |
1dd538f07 cpufreq: add imx6... |
340 |
if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) || |
ced7bc8de MLK-11343-02 cpuf... |
341 342 |
IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk) || IS_ERR(pll1) || IS_ERR(pll1_bypass) || IS_ERR(pll1_bypass_src)) { |
1dd538f07 cpufreq: add imx6... |
343 344 345 |
dev_err(cpu_dev, "failed to get clocks "); ret = -ENOENT; |
90ee80a6f MLK-14301: Revert... |
346 |
goto put_clk; |
1dd538f07 cpufreq: add imx6... |
347 |
} |
c97fa8900 MLK-14624 cpufreq... |
348 349 |
if (of_machine_is_compatible("fsl,imx6ul") || of_machine_is_compatible("fsl,imx6ull")) { |
a35fc5a33 cpufreq: imx: upd... |
350 351 352 353 354 355 |
pll2_bus_clk = clk_get(cpu_dev, "pll2_bus"); secondary_sel_clk = clk_get(cpu_dev, "secondary_sel"); if (IS_ERR(pll2_bus_clk) || IS_ERR(secondary_sel_clk)) { dev_err(cpu_dev, "failed to get clocks specific to imx6ul "); ret = -ENOENT; |
90ee80a6f MLK-14301: Revert... |
356 |
goto put_clk; |
a35fc5a33 cpufreq: imx: upd... |
357 358 |
} } |
90ee80a6f MLK-14301: Revert... |
359 360 |
vpu_axi_podf = clk_get(cpu_dev, "vpu_axi_podf"); if (!IS_ERR(vpu_axi_podf)) { |
602a44634 MLK-13119-3 cpufr... |
361 |
vpu_axi_rate = clk_get_rate(vpu_axi_podf); |
90ee80a6f MLK-14301: Revert... |
362 363 |
clk_put(vpu_axi_podf); } |
602a44634 MLK-13119-3 cpufr... |
364 |
|
90ee80a6f MLK-14301: Revert... |
365 366 367 |
arm_reg = regulator_get(cpu_dev, "arm"); pu_reg = regulator_get_optional(cpu_dev, "pu"); soc_reg = regulator_get(cpu_dev, "soc"); |
22d0628a2 cpufreq: imx6: re... |
368 |
if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) { |
a544de724 MLK-13793-1 cpufr... |
369 370 371 372 373 374 375 |
ret = IS_ERR(arm_reg)?PTR_ERR(arm_reg):PTR_ERR(soc_reg); if (ret == -EPROBE_DEFER) dev_warn(cpu_dev, "regulators not ready, retry "); else dev_err(cpu_dev, "failed to get regulators: %d ", ret); |
90ee80a6f MLK-14301: Revert... |
376 |
goto put_reg; |
1dd538f07 cpufreq: add imx6... |
377 |
} |
90ee80a6f MLK-14301: Revert... |
378 |
dc_reg = regulator_get_optional(cpu_dev, "dc"); |
1a4dd3071 MLK-11252-02 cpuf... |
379 |
|
20b7cbe29 cpufreq: imx6q: a... |
380 |
/* |
fe3aca041 MLK-10073-3 cpufr... |
381 382 383 384 385 386 387 388 389 |
* soc_reg sync with arm_reg if arm shares the same regulator * with soc. Otherwise, regulator common framework will refuse to update * this consumer's voltage right now while another consumer voltage * still keep in old one. For example, imx6sx-sdb with pfuze200 in * ldo-bypass mode. */ of_property_read_u32(np, "fsl,arm-soc-shared", &i); if (i == 1) soc_reg = arm_reg; |
1d733f828 MLK-13133-02 cpuf... |
390 391 392 |
/* On i.MX6ULL, check the 24MHz low power run mode support */ low_power_run_support = of_property_read_bool(np, "fsl,low-power-run"); |
fe3aca041 MLK-10073-3 cpufr... |
393 |
/* |
20b7cbe29 cpufreq: imx6q: a... |
394 395 396 397 |
* We expect an OPP table supplied by platform. * Just, incase the platform did not supply the OPP * table, it will try to get it. */ |
5d4879cda PM / OPP: rename ... |
398 |
num = dev_pm_opp_get_opp_count(cpu_dev); |
1dd538f07 cpufreq: add imx6... |
399 |
if (num < 0) { |
8f8d37b25 PM / OPP: Prefix ... |
400 |
ret = dev_pm_opp_of_add_table(cpu_dev); |
20b7cbe29 cpufreq: imx6q: a... |
401 402 403 |
if (ret < 0) { dev_err(cpu_dev, "failed to init OPP table: %d ", ret); |
90ee80a6f MLK-14301: Revert... |
404 |
goto put_reg; |
20b7cbe29 cpufreq: imx6q: a... |
405 |
} |
cc87b8a8e imx6q: free OPP t... |
406 407 |
/* Because we have added the OPPs here, we must free them */ free_opp = true; |
20b7cbe29 cpufreq: imx6q: a... |
408 409 410 411 412 |
num = dev_pm_opp_get_opp_count(cpu_dev); if (num < 0) { ret = num; dev_err(cpu_dev, "no OPP table is found: %d ", ret); |
cc87b8a8e imx6q: free OPP t... |
413 |
goto out_free_opp; |
20b7cbe29 cpufreq: imx6q: a... |
414 |
} |
1dd538f07 cpufreq: add imx6... |
415 |
} |
5d4879cda PM / OPP: rename ... |
416 |
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); |
1dd538f07 cpufreq: add imx6... |
417 418 419 |
if (ret) { dev_err(cpu_dev, "failed to init cpufreq table: %d ", ret); |
90ee80a6f MLK-14301: Revert... |
420 |
goto put_reg; |
1dd538f07 cpufreq: add imx6... |
421 |
} |
6babbe05d MLK-12623-01 cpuf... |
422 |
/* |
90ff4d1c3 MLK-14747 driver:... |
423 |
* On i.MX6UL/ULL EVK board, if the SOC is run in overide frequency, |
6babbe05d MLK-12623-01 cpuf... |
424 425 |
* the dc_regulator voltage should not be touched. */ |
90ff4d1c3 MLK-14747 driver:... |
426 |
if (freq_table[num - 1].frequency > FREQ_528_MHZ) |
6babbe05d MLK-12623-01 cpuf... |
427 428 429 |
ignore_dc_reg = true; if (!IS_ERR(dc_reg) && !ignore_dc_reg) regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0); |
b4573d1d6 cpufreq: imx6q: c... |
430 |
/* Make imx6_soc_volt array's size same as arm opp number */ |
90ee80a6f MLK-14301: Revert... |
431 |
imx6_soc_volt = kzalloc(sizeof(*imx6_soc_volt) * num, GFP_KERNEL); |
b4573d1d6 cpufreq: imx6q: c... |
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
if (imx6_soc_volt == NULL) { ret = -ENOMEM; goto free_freq_table; } prop = of_find_property(np, "fsl,soc-operating-points", NULL); if (!prop || !prop->value) goto soc_opp_out; /* * Each OPP is a set of tuples consisting of frequency and * voltage like <freq-kHz vol-uV>. */ nr = prop->length / sizeof(u32); if (nr % 2 || (nr / 2) < num) goto soc_opp_out; for (j = 0; j < num; j++) { val = prop->value; for (i = 0; i < nr / 2; i++) { unsigned long freq = be32_to_cpup(val++); unsigned long volt = be32_to_cpup(val++); if (freq_table[j].frequency == freq) { imx6_soc_volt[soc_opp_count++] = volt; |
40fb857f8 MLK-10103-2 cpufr... |
456 457 458 459 460 461 462 |
#ifdef CONFIG_MX6_VPU_352M if (freq == 792000) { pr_info("increase SOC/PU voltage for VPU352MHz "); imx6_soc_volt[soc_opp_count - 1] = 1250000; } #endif |
602a44634 MLK-13119-3 cpufr... |
463 464 465 466 467 468 469 470 |
if (vpu_axi_rate == 396000000) { if (freq <= 996000) { pr_info("increase SOC/PU voltage for VPU396MHz at %ld MHz ", freq / 1000); imx6_soc_volt[soc_opp_count - 1] = 1275000; } } |
b4573d1d6 cpufreq: imx6q: c... |
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
break; } } } soc_opp_out: /* use fixed soc opp volt if no valid soc opp info found in dtb */ if (soc_opp_count != num) { dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value! "); for (j = 0; j < num; j++) imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL; if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ) imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH; } |
1dd538f07 cpufreq: add imx6... |
486 487 488 489 |
if (of_property_read_u32(np, "clock-latency", &transition_latency)) transition_latency = CPUFREQ_ETERNAL; /* |
b4573d1d6 cpufreq: imx6q: c... |
490 491 492 493 494 495 |
* Calculate the ramp time for max voltage change in the * VDDSOC and VDDPU regulators. */ ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); if (ret > 0) transition_latency += ret * 1000; |
22d0628a2 cpufreq: imx6: re... |
496 497 498 499 500 |
if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); if (ret > 0) transition_latency += ret * 1000; } |
b4573d1d6 cpufreq: imx6q: c... |
501 502 |
/* |
1dd538f07 cpufreq: add imx6... |
503 504 505 506 507 |
* OPP is maintained in order of increasing frequency, and * freq_table initialised from OPP is therefore sorted in the * same order. */ rcu_read_lock(); |
5d4879cda PM / OPP: rename ... |
508 |
opp = dev_pm_opp_find_freq_exact(cpu_dev, |
1dd538f07 cpufreq: add imx6... |
509 |
freq_table[0].frequency * 1000, true); |
5d4879cda PM / OPP: rename ... |
510 511 |
min_volt = dev_pm_opp_get_voltage(opp); opp = dev_pm_opp_find_freq_exact(cpu_dev, |
1dd538f07 cpufreq: add imx6... |
512 |
freq_table[--num].frequency * 1000, true); |
5d4879cda PM / OPP: rename ... |
513 |
max_volt = dev_pm_opp_get_voltage(opp); |
1dd538f07 cpufreq: add imx6... |
514 515 516 517 |
rcu_read_unlock(); ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); if (ret > 0) transition_latency += ret * 1000; |
62300a004 MLK-9693 cpufreq:... |
518 |
mutex_init(&set_cpufreq_lock); |
1dd538f07 cpufreq: add imx6... |
519 520 521 522 523 524 |
ret = cpufreq_register_driver(&imx6q_cpufreq_driver); if (ret) { dev_err(cpu_dev, "failed register driver: %d ", ret); goto free_freq_table; } |
62300a004 MLK-9693 cpufreq:... |
525 |
register_pm_notifier(&imx6_cpufreq_pm_notifier); |
1dd538f07 cpufreq: add imx6... |
526 |
of_node_put(np); |
a544de724 MLK-13793-1 cpufr... |
527 528 |
dev_info(cpu_dev, "Registered imx6q-cpufreq "); |
1dd538f07 cpufreq: add imx6... |
529 530 531 |
return 0; free_freq_table: |
90ee80a6f MLK-14301: Revert... |
532 |
kfree(imx6_soc_volt); |
5d4879cda PM / OPP: rename ... |
533 |
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); |
cc87b8a8e imx6q: free OPP t... |
534 535 |
out_free_opp: if (free_opp) |
8f8d37b25 PM / OPP: Prefix ... |
536 |
dev_pm_opp_of_remove_table(cpu_dev); |
90ee80a6f MLK-14301: Revert... |
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 |
put_reg: if (!IS_ERR(arm_reg)) regulator_put(arm_reg); if (!IS_ERR(pu_reg)) regulator_put(pu_reg); if (!IS_ERR(soc_reg)) regulator_put(soc_reg); if (!IS_ERR(dc_reg)) regulator_put(dc_reg); put_clk: if (!IS_ERR(arm_clk)) clk_put(arm_clk); if (!IS_ERR(pll1_sys_clk)) clk_put(pll1_sys_clk); if (!IS_ERR(pll1_sw_clk)) clk_put(pll1_sw_clk); if (!IS_ERR(step_clk)) clk_put(step_clk); if (!IS_ERR(pll2_pfd2_396m_clk)) clk_put(pll2_pfd2_396m_clk); if (!IS_ERR(pll1)) clk_put(pll1); if (!IS_ERR(pll1_bypass)) clk_put(pll1_bypass); if (!IS_ERR(pll1_bypass_src)) clk_put(pll1_bypass_src); if (!IS_ERR(pll2_bus_clk)) clk_put(pll2_bus_clk); if (!IS_ERR(secondary_sel_clk)) clk_put(secondary_sel_clk); |
1dd538f07 cpufreq: add imx6... |
567 568 569 570 571 572 573 |
of_node_put(np); return ret; } static int imx6q_cpufreq_remove(struct platform_device *pdev) { cpufreq_unregister_driver(&imx6q_cpufreq_driver); |
90ee80a6f MLK-14301: Revert... |
574 |
kfree(imx6_soc_volt); |
5d4879cda PM / OPP: rename ... |
575 |
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); |
cc87b8a8e imx6q: free OPP t... |
576 |
if (free_opp) |
8f8d37b25 PM / OPP: Prefix ... |
577 |
dev_pm_opp_of_remove_table(cpu_dev); |
90ee80a6f MLK-14301: Revert... |
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
regulator_put(arm_reg); if (!IS_ERR(pu_reg)) regulator_put(pu_reg); regulator_put(soc_reg); if (!IS_ERR(dc_reg)) regulator_put(dc_reg); clk_put(arm_clk); clk_put(pll1_sys_clk); clk_put(pll1_sw_clk); clk_put(step_clk); clk_put(pll1); clk_put(pll1_bypass); clk_put(pll1_bypass_src); clk_put(pll2_pfd2_396m_clk); clk_put(pll2_bus_clk); clk_put(secondary_sel_clk); |
1dd538f07 cpufreq: add imx6... |
594 595 596 597 598 599 600 |
return 0; } static struct platform_driver imx6q_cpufreq_platdrv = { .driver = { .name = "imx6q-cpufreq", |
1dd538f07 cpufreq: add imx6... |
601 602 603 604 605 606 607 608 609 |
}, .probe = imx6q_cpufreq_probe, .remove = imx6q_cpufreq_remove, }; module_platform_driver(imx6q_cpufreq_platdrv); MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver"); MODULE_LICENSE("GPL"); |