aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLin Huang <hl@rock-chips.com>2016-09-05 01:06:10 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2016-09-06 00:26:34 -0400
commit5a893e31a636cca3798af2db5aee8d3d144b1e1e (patch)
treecfd450bf7e6e795fa701ae616f3090733d7af82c
parentc1ceb8f7c167eeae79e083417cce8995de3b9238 (diff)
PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang <hl@rock-chips.com> Signed-off-by: MyngJoo Ham <myngjoo.ham@samsung.com> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--drivers/devfreq/Kconfig11
-rw-r--r--drivers/devfreq/Makefile1
-rw-r--r--drivers/devfreq/rk3399_dmc.c480
3 files changed, 492 insertions, 0 deletions
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index f08502c27784..cadd56e50b2c 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -100,6 +100,17 @@ config ARM_TEGRA_DEVFREQ
100 It reads ACTMON counters of memory controllers and adjusts the 100 It reads ACTMON counters of memory controllers and adjusts the
101 operating frequencies and voltages with OPP support. 101 operating frequencies and voltages with OPP support.
102 102
103config ARM_RK3399_DMC_DEVFREQ
104 tristate "ARM RK3399 DMC DEVFREQ Driver"
105 depends on ARCH_ROCKCHIP
106 select DEVFREQ_EVENT_ROCKCHIP_DFI
107 select DEVFREQ_GOV_SIMPLE_ONDEMAND
108 select PM_OPP
109 help
110 This adds the DEVFREQ driver for the RK3399 DMC(Dynamic Memory Controller).
111 It sets the frequency for the memory controller and reads the usage counts
112 from hardware.
113
103source "drivers/devfreq/event/Kconfig" 114source "drivers/devfreq/event/Kconfig"
104 115
105endif # PM_DEVFREQ 116endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 09f11d9d40d5..fbff40a508a4 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
8 8
9# DEVFREQ Drivers 9# DEVFREQ Drivers
10obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o 10obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
11obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
11obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o 12obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o
12 13
13# DEVFREQ Event Drivers 14# DEVFREQ Event Drivers
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
new file mode 100644
index 000000000000..54d65f24a9fe
--- /dev/null
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -0,0 +1,480 @@
1/*
2 * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd.
3 * Author: Lin Huang <hl@rock-chips.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/arm-smccc.h>
16#include <linux/clk.h>
17#include <linux/delay.h>
18#include <linux/devfreq.h>
19#include <linux/devfreq-event.h>
20#include <linux/interrupt.h>
21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/platform_device.h>
24#include <linux/pm_opp.h>
25#include <linux/regulator/consumer.h>
26#include <linux/rwsem.h>
27#include <linux/suspend.h>
28
29#include <soc/rockchip/rockchip_sip.h>
30
31struct dram_timing {
32 unsigned int ddr3_speed_bin;
33 unsigned int pd_idle;
34 unsigned int sr_idle;
35 unsigned int sr_mc_gate_idle;
36 unsigned int srpd_lite_idle;
37 unsigned int standby_idle;
38 unsigned int auto_pd_dis_freq;
39 unsigned int dram_dll_dis_freq;
40 unsigned int phy_dll_dis_freq;
41 unsigned int ddr3_odt_dis_freq;
42 unsigned int ddr3_drv;
43 unsigned int ddr3_odt;
44 unsigned int phy_ddr3_ca_drv;
45 unsigned int phy_ddr3_dq_drv;
46 unsigned int phy_ddr3_odt;
47 unsigned int lpddr3_odt_dis_freq;
48 unsigned int lpddr3_drv;
49 unsigned int lpddr3_odt;
50 unsigned int phy_lpddr3_ca_drv;
51 unsigned int phy_lpddr3_dq_drv;
52 unsigned int phy_lpddr3_odt;
53 unsigned int lpddr4_odt_dis_freq;
54 unsigned int lpddr4_drv;
55 unsigned int lpddr4_dq_odt;
56 unsigned int lpddr4_ca_odt;
57 unsigned int phy_lpddr4_ca_drv;
58 unsigned int phy_lpddr4_ck_cs_drv;
59 unsigned int phy_lpddr4_dq_drv;
60 unsigned int phy_lpddr4_odt;
61};
62
63struct rk3399_dmcfreq {
64 struct device *dev;
65 struct devfreq *devfreq;
66 struct devfreq_simple_ondemand_data ondemand_data;
67 struct clk *dmc_clk;
68 struct devfreq_event_dev *edev;
69 struct mutex lock;
70 struct dram_timing timing;
71
72 /*
73 * DDR Converser of Frequency (DCF) is used to implement DDR frequency
74 * conversion without the participation of CPU, we will implement and
75 * control it in arm trust firmware.
76 */
77 wait_queue_head_t wait_dcf_queue;
78 int irq;
79 int wait_dcf_flag;
80 struct regulator *vdd_center;
81 unsigned long rate, target_rate;
82 unsigned long volt, target_volt;
83 struct dev_pm_opp *curr_opp;
84};
85
86static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
87 u32 flags)
88{
89 struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
90 struct dev_pm_opp *opp;
91 unsigned long old_clk_rate = dmcfreq->rate;
92 unsigned long target_volt, target_rate;
93 int err;
94
95 rcu_read_lock();
96 opp = devfreq_recommended_opp(dev, freq, flags);
97 if (IS_ERR(opp)) {
98 rcu_read_unlock();
99 return PTR_ERR(opp);
100 }
101
102 target_rate = dev_pm_opp_get_freq(opp);
103 target_volt = dev_pm_opp_get_voltage(opp);
104
105 dmcfreq->rate = dev_pm_opp_get_freq(dmcfreq->curr_opp);
106 dmcfreq->volt = dev_pm_opp_get_voltage(dmcfreq->curr_opp);
107
108 rcu_read_unlock();
109
110 if (dmcfreq->rate == target_rate)
111 return 0;
112
113 mutex_lock(&dmcfreq->lock);
114
115 /*
116 * If frequency scaling from low to high, adjust voltage first.
117 * If frequency scaling from high to low, adjust frequency first.
118 */
119 if (old_clk_rate < target_rate) {
120 err = regulator_set_voltage(dmcfreq->vdd_center, target_volt,
121 target_volt);
122 if (err) {
123 dev_err(dev, "Cannot to set voltage %lu uV\n",
124 target_volt);
125 goto out;
126 }
127 }
128 dmcfreq->wait_dcf_flag = 1;
129
130 err = clk_set_rate(dmcfreq->dmc_clk, target_rate);
131 if (err) {
132 dev_err(dev, "Cannot to set frequency %lu (%d)\n",
133 target_rate, err);
134 regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt,
135 dmcfreq->volt);
136 goto out;
137 }
138
139 /*
140 * Wait until bcf irq happen, it means freq scaling finish in
141 * arm trust firmware, use 100ms as timeout time.
142 */
143 if (!wait_event_timeout(dmcfreq->wait_dcf_queue,
144 !dmcfreq->wait_dcf_flag, HZ / 10))
145 dev_warn(dev, "Timeout waiting for dcf interrupt\n");
146
147 /*
148 * Check the dpll rate,
149 * There only two result we will get,
150 * 1. Ddr frequency scaling fail, we still get the old rate.
151 * 2. Ddr frequency scaling sucessful, we get the rate we set.
152 */
153 dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk);
154
155 /* If get the incorrect rate, set voltage to old value. */
156 if (dmcfreq->rate != target_rate) {
157 dev_err(dev, "Get wrong ddr frequency, Request frequency %lu,\
158 Current frequency %lu\n", target_rate, dmcfreq->rate);
159 regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt,
160 dmcfreq->volt);
161 goto out;
162 } else if (old_clk_rate > target_rate)
163 err = regulator_set_voltage(dmcfreq->vdd_center, target_volt,
164 target_volt);
165 if (err)
166 dev_err(dev, "Cannot to set vol %lu uV\n", target_volt);
167
168 dmcfreq->curr_opp = opp;
169out:
170 mutex_unlock(&dmcfreq->lock);
171 return err;
172}
173
174static int rk3399_dmcfreq_get_dev_status(struct device *dev,
175 struct devfreq_dev_status *stat)
176{
177 struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
178 struct devfreq_event_data edata;
179 int ret = 0;
180
181 ret = devfreq_event_get_event(dmcfreq->edev, &edata);
182 if (ret < 0)
183 return ret;
184
185 stat->current_frequency = dmcfreq->rate;
186 stat->busy_time = edata.load_count;
187 stat->total_time = edata.total_count;
188
189 return ret;
190}
191
192static int rk3399_dmcfreq_get_cur_freq(struct device *dev, unsigned long *freq)
193{
194 struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
195
196 *freq = dmcfreq->rate;
197
198 return 0;
199}
200
201static struct devfreq_dev_profile rk3399_devfreq_dmc_profile = {
202 .polling_ms = 200,
203 .target = rk3399_dmcfreq_target,
204 .get_dev_status = rk3399_dmcfreq_get_dev_status,
205 .get_cur_freq = rk3399_dmcfreq_get_cur_freq,
206};
207
208static __maybe_unused int rk3399_dmcfreq_suspend(struct device *dev)
209{
210 struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
211 int ret = 0;
212
213 ret = devfreq_event_disable_edev(dmcfreq->edev);
214 if (ret < 0) {
215 dev_err(dev, "failed to disable the devfreq-event devices\n");
216 return ret;
217 }
218
219 ret = devfreq_suspend_device(dmcfreq->devfreq);
220 if (ret < 0) {
221 dev_err(dev, "failed to suspend the devfreq devices\n");
222 return ret;
223 }
224
225 return 0;
226}
227
228static __maybe_unused int rk3399_dmcfreq_resume(struct device *dev)
229{
230 struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
231 int ret = 0;
232
233 ret = devfreq_event_enable_edev(dmcfreq->edev);
234 if (ret < 0) {
235 dev_err(dev, "failed to enable the devfreq-event devices\n");
236 return ret;
237 }
238
239 ret = devfreq_resume_device(dmcfreq->devfreq);
240 if (ret < 0) {
241 dev_err(dev, "failed to resume the devfreq devices\n");
242 return ret;
243 }
244 return ret;
245}
246
247static SIMPLE_DEV_PM_OPS(rk3399_dmcfreq_pm, rk3399_dmcfreq_suspend,
248 rk3399_dmcfreq_resume);
249
250static irqreturn_t rk3399_dmc_irq(int irq, void *dev_id)
251{
252 struct rk3399_dmcfreq *dmcfreq = dev_id;
253 struct arm_smccc_res res;
254
255 dmcfreq->wait_dcf_flag = 0;
256 wake_up(&dmcfreq->wait_dcf_queue);
257
258 /* Clear the DCF interrupt */
259 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
260 ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ,
261 0, 0, 0, 0, &res);
262
263 return IRQ_HANDLED;
264}
265
266static int of_get_ddr_timings(struct dram_timing *timing,
267 struct device_node *np)
268{
269 int ret = 0;
270
271 ret = of_property_read_u32(np, "rockchip,ddr3_speed_bin",
272 &timing->ddr3_speed_bin);
273 ret |= of_property_read_u32(np, "rockchip,pd_idle",
274 &timing->pd_idle);
275 ret |= of_property_read_u32(np, "rockchip,sr_idle",
276 &timing->sr_idle);
277 ret |= of_property_read_u32(np, "rockchip,sr_mc_gate_idle",
278 &timing->sr_mc_gate_idle);
279 ret |= of_property_read_u32(np, "rockchip,srpd_lite_idle",
280 &timing->srpd_lite_idle);
281 ret |= of_property_read_u32(np, "rockchip,standby_idle",
282 &timing->standby_idle);
283 ret |= of_property_read_u32(np, "rockchip,auto_pd_dis_freq",
284 &timing->auto_pd_dis_freq);
285 ret |= of_property_read_u32(np, "rockchip,dram_dll_dis_freq",
286 &timing->dram_dll_dis_freq);
287 ret |= of_property_read_u32(np, "rockchip,phy_dll_dis_freq",
288 &timing->phy_dll_dis_freq);
289 ret |= of_property_read_u32(np, "rockchip,ddr3_odt_dis_freq",
290 &timing->ddr3_odt_dis_freq);
291 ret |= of_property_read_u32(np, "rockchip,ddr3_drv",
292 &timing->ddr3_drv);
293 ret |= of_property_read_u32(np, "rockchip,ddr3_odt",
294 &timing->ddr3_odt);
295 ret |= of_property_read_u32(np, "rockchip,phy_ddr3_ca_drv",
296 &timing->phy_ddr3_ca_drv);
297 ret |= of_property_read_u32(np, "rockchip,phy_ddr3_dq_drv",
298 &timing->phy_ddr3_dq_drv);
299 ret |= of_property_read_u32(np, "rockchip,phy_ddr3_odt",
300 &timing->phy_ddr3_odt);
301 ret |= of_property_read_u32(np, "rockchip,lpddr3_odt_dis_freq",
302 &timing->lpddr3_odt_dis_freq);
303 ret |= of_property_read_u32(np, "rockchip,lpddr3_drv",
304 &timing->lpddr3_drv);
305 ret |= of_property_read_u32(np, "rockchip,lpddr3_odt",
306 &timing->lpddr3_odt);
307 ret |= of_property_read_u32(np, "rockchip,phy_lpddr3_ca_drv",
308 &timing->phy_lpddr3_ca_drv);
309 ret |= of_property_read_u32(np, "rockchip,phy_lpddr3_dq_drv",
310 &timing->phy_lpddr3_dq_drv);
311 ret |= of_property_read_u32(np, "rockchip,phy_lpddr3_odt",
312 &timing->phy_lpddr3_odt);
313 ret |= of_property_read_u32(np, "rockchip,lpddr4_odt_dis_freq",
314 &timing->lpddr4_odt_dis_freq);
315 ret |= of_property_read_u32(np, "rockchip,lpddr4_drv",
316 &timing->lpddr4_drv);
317 ret |= of_property_read_u32(np, "rockchip,lpddr4_dq_odt",
318 &timing->lpddr4_dq_odt);
319 ret |= of_property_read_u32(np, "rockchip,lpddr4_ca_odt",
320 &timing->lpddr4_ca_odt);
321 ret |= of_property_read_u32(np, "rockchip,phy_lpddr4_ca_drv",
322 &timing->phy_lpddr4_ca_drv);
323 ret |= of_property_read_u32(np, "rockchip,phy_lpddr4_ck_cs_drv",
324 &timing->phy_lpddr4_ck_cs_drv);
325 ret |= of_property_read_u32(np, "rockchip,phy_lpddr4_dq_drv",
326 &timing->phy_lpddr4_dq_drv);
327 ret |= of_property_read_u32(np, "rockchip,phy_lpddr4_odt",
328 &timing->phy_lpddr4_odt);
329
330 return ret;
331}
332
333static int rk3399_dmcfreq_probe(struct platform_device *pdev)
334{
335 struct arm_smccc_res res;
336 struct device *dev = &pdev->dev;
337 struct device_node *np = pdev->dev.of_node;
338 struct rk3399_dmcfreq *data;
339 int ret, irq, index, size;
340 uint32_t *timing;
341 struct dev_pm_opp *opp;
342
343 irq = platform_get_irq(pdev, 0);
344 if (irq < 0) {
345 dev_err(&pdev->dev, "Cannot get the dmc interrupt resource\n");
346 return -EINVAL;
347 }
348 data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
349 if (!data)
350 return -ENOMEM;
351
352 mutex_init(&data->lock);
353
354 data->vdd_center = devm_regulator_get(dev, "center");
355 if (IS_ERR(data->vdd_center)) {
356 dev_err(dev, "Cannot get the regulator \"center\"\n");
357 return PTR_ERR(data->vdd_center);
358 }
359
360 data->dmc_clk = devm_clk_get(dev, "dmc_clk");
361 if (IS_ERR(data->dmc_clk)) {
362 dev_err(dev, "Cannot get the clk dmc_clk\n");
363 return PTR_ERR(data->dmc_clk);
364 };
365
366 data->irq = irq;
367 ret = devm_request_irq(dev, irq, rk3399_dmc_irq, 0,
368 dev_name(dev), data);
369 if (ret) {
370 dev_err(dev, "Failed to request dmc irq: %d\n", ret);
371 return ret;
372 }
373
374 init_waitqueue_head(&data->wait_dcf_queue);
375 data->wait_dcf_flag = 0;
376
377 data->edev = devfreq_event_get_edev_by_phandle(dev, 0);
378 if (IS_ERR(data->edev))
379 return -EPROBE_DEFER;
380
381 ret = devfreq_event_enable_edev(data->edev);
382 if (ret < 0) {
383 dev_err(dev, "failed to enable devfreq-event devices\n");
384 return ret;
385 }
386
387 /*
388 * Get dram timing and pass it to arm trust firmware,
389 * the dram drvier in arm trust firmware will get these
390 * timing and to do dram initial.
391 */
392 if (!of_get_ddr_timings(&data->timing, np)) {
393 timing = &data->timing.ddr3_speed_bin;
394 size = sizeof(struct dram_timing) / 4;
395 for (index = 0; index < size; index++) {
396 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, *timing++, index,
397 ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM,
398 0, 0, 0, 0, &res);
399 if (res.a0) {
400 dev_err(dev, "Failed to set dram param: %ld\n",
401 res.a0);
402 return -EINVAL;
403 }
404 }
405 }
406
407 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
408 ROCKCHIP_SIP_CONFIG_DRAM_INIT,
409 0, 0, 0, 0, &res);
410
411 /*
412 * We add a devfreq driver to our parent since it has a device tree node
413 * with operating points.
414 */
415 if (dev_pm_opp_of_add_table(dev)) {
416 dev_err(dev, "Invalid operating-points in device tree.\n");
417 rcu_read_unlock();
418 return -EINVAL;
419 }
420
421 of_property_read_u32(np, "upthreshold",
422 &data->ondemand_data.upthreshold);
423 of_property_read_u32(np, "downdifferential",
424 &data->ondemand_data.downdifferential);
425
426 data->rate = clk_get_rate(data->dmc_clk);
427
428 rcu_read_lock();
429 opp = devfreq_recommended_opp(dev, &data->rate, 0);
430 if (IS_ERR(opp)) {
431 rcu_read_unlock();
432 return PTR_ERR(opp);
433 }
434 rcu_read_unlock();
435 data->curr_opp = opp;
436
437 rk3399_devfreq_dmc_profile.initial_freq = data->rate;
438
439 data->devfreq = devfreq_add_device(dev,
440 &rk3399_devfreq_dmc_profile,
441 "simple_ondemand",
442 &data->ondemand_data);
443 if (IS_ERR(data->devfreq))
444 return PTR_ERR(data->devfreq);
445 devm_devfreq_register_opp_notifier(dev, data->devfreq);
446
447 data->dev = dev;
448 platform_set_drvdata(pdev, data);
449
450 return 0;
451}
452
453static int rk3399_dmcfreq_remove(struct platform_device *pdev)
454{
455 struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev);
456
457 regulator_put(dmcfreq->vdd_center);
458
459 return 0;
460}
461
462static const struct of_device_id rk3399dmc_devfreq_of_match[] = {
463 { .compatible = "rockchip,rk3399-dmc" },
464 { },
465};
466
467static struct platform_driver rk3399_dmcfreq_driver = {
468 .probe = rk3399_dmcfreq_probe,
469 .remove = rk3399_dmcfreq_remove,
470 .driver = {
471 .name = "rk3399-dmc-freq",
472 .pm = &rk3399_dmcfreq_pm,
473 .of_match_table = rk3399dmc_devfreq_of_match,
474 },
475};
476module_platform_driver(rk3399_dmcfreq_driver);
477
478MODULE_LICENSE("GPL v2");
479MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>");
480MODULE_DESCRIPTION("RK3399 dmcfreq driver with devfreq framework");