summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEnric Balletbo i Serra <enric.balletbo@collabora.com>2019-03-21 19:14:38 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2019-04-15 20:29:18 -0400
commit9173c5ceb035aab28171cd74dfddf27f47213b99 (patch)
tree119a090f9d37e7281c6d807b18c838b3b1131ffa
parentadfe3b76608ffe547af5a74415f15499b798f32a (diff)
PM / devfreq: rk3399_dmc: Pass ODT and auto power down parameters to TF-A.
Trusted Firmware-A (TF-A) for rk3399 implements a SiP call to get the on-die termination (ODT) and auto power down parameters from kernel, this patch adds the functionality to do this. Also, if DDR clock frequency is lower than the on-die termination (ODT) disable frequency this driver should disable the DDR ODT. Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Gaƫl PORTAY <gael.portay@collabora.com> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
-rw-r--r--drivers/devfreq/rk3399_dmc.c71
-rw-r--r--include/soc/rockchip/rockchip_sip.h1
2 files changed, 71 insertions, 1 deletions
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index a228dad2bee4..567c034d0301 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -18,14 +18,17 @@
18#include <linux/devfreq.h> 18#include <linux/devfreq.h>
19#include <linux/devfreq-event.h> 19#include <linux/devfreq-event.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/mfd/syscon.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/of.h> 23#include <linux/of.h>
23#include <linux/platform_device.h> 24#include <linux/platform_device.h>
24#include <linux/pm_opp.h> 25#include <linux/pm_opp.h>
26#include <linux/regmap.h>
25#include <linux/regulator/consumer.h> 27#include <linux/regulator/consumer.h>
26#include <linux/rwsem.h> 28#include <linux/rwsem.h>
27#include <linux/suspend.h> 29#include <linux/suspend.h>
28 30
31#include <soc/rockchip/rk3399_grf.h>
29#include <soc/rockchip/rockchip_sip.h> 32#include <soc/rockchip/rockchip_sip.h>
30 33
31struct dram_timing { 34struct dram_timing {
@@ -69,8 +72,11 @@ struct rk3399_dmcfreq {
69 struct mutex lock; 72 struct mutex lock;
70 struct dram_timing timing; 73 struct dram_timing timing;
71 struct regulator *vdd_center; 74 struct regulator *vdd_center;
75 struct regmap *regmap_pmu;
72 unsigned long rate, target_rate; 76 unsigned long rate, target_rate;
73 unsigned long volt, target_volt; 77 unsigned long volt, target_volt;
78 unsigned int odt_dis_freq;
79 int odt_pd_arg0, odt_pd_arg1;
74}; 80};
75 81
76static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, 82static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
@@ -80,6 +86,8 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
80 struct dev_pm_opp *opp; 86 struct dev_pm_opp *opp;
81 unsigned long old_clk_rate = dmcfreq->rate; 87 unsigned long old_clk_rate = dmcfreq->rate;
82 unsigned long target_volt, target_rate; 88 unsigned long target_volt, target_rate;
89 struct arm_smccc_res res;
90 bool odt_enable = false;
83 int err; 91 int err;
84 92
85 opp = devfreq_recommended_opp(dev, freq, flags); 93 opp = devfreq_recommended_opp(dev, freq, flags);
@@ -95,6 +103,19 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
95 103
96 mutex_lock(&dmcfreq->lock); 104 mutex_lock(&dmcfreq->lock);
97 105
106 if (target_rate >= dmcfreq->odt_dis_freq)
107 odt_enable = true;
108
109 /*
110 * This makes a SMC call to the TF-A to set the DDR PD (power-down)
111 * timings and to enable or disable the ODT (on-die termination)
112 * resistors.
113 */
114 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
115 dmcfreq->odt_pd_arg1,
116 ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
117 odt_enable, 0, 0, 0, &res);
118
98 /* 119 /*
99 * If frequency scaling from low to high, adjust voltage first. 120 * If frequency scaling from low to high, adjust voltage first.
100 * If frequency scaling from high to low, adjust frequency first. 121 * If frequency scaling from high to low, adjust frequency first.
@@ -294,11 +315,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
294{ 315{
295 struct arm_smccc_res res; 316 struct arm_smccc_res res;
296 struct device *dev = &pdev->dev; 317 struct device *dev = &pdev->dev;
297 struct device_node *np = pdev->dev.of_node; 318 struct device_node *np = pdev->dev.of_node, *node;
298 struct rk3399_dmcfreq *data; 319 struct rk3399_dmcfreq *data;
299 int ret, index, size; 320 int ret, index, size;
300 uint32_t *timing; 321 uint32_t *timing;
301 struct dev_pm_opp *opp; 322 struct dev_pm_opp *opp;
323 u32 ddr_type;
324 u32 val;
302 325
303 data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL); 326 data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
304 if (!data) 327 if (!data)
@@ -354,11 +377,57 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
354 } 377 }
355 } 378 }
356 379
380 node = of_parse_phandle(np, "rockchip,pmu", 0);
381 if (node) {
382 data->regmap_pmu = syscon_node_to_regmap(node);
383 if (IS_ERR(data->regmap_pmu))
384 return PTR_ERR(data->regmap_pmu);
385 }
386
387 regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
388 ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) &
389 RK3399_PMUGRF_DDRTYPE_MASK;
390
391 switch (ddr_type) {
392 case RK3399_PMUGRF_DDRTYPE_DDR3:
393 data->odt_dis_freq = data->timing.ddr3_odt_dis_freq;
394 break;
395 case RK3399_PMUGRF_DDRTYPE_LPDDR3:
396 data->odt_dis_freq = data->timing.lpddr3_odt_dis_freq;
397 break;
398 case RK3399_PMUGRF_DDRTYPE_LPDDR4:
399 data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
400 break;
401 default:
402 return -EINVAL;
403 };
404
357 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0, 405 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
358 ROCKCHIP_SIP_CONFIG_DRAM_INIT, 406 ROCKCHIP_SIP_CONFIG_DRAM_INIT,
359 0, 0, 0, 0, &res); 407 0, 0, 0, 0, &res);
360 408
361 /* 409 /*
410 * In TF-A there is a platform SIP call to set the PD (power-down)
411 * timings and to enable or disable the ODT (on-die termination).
412 * This call needs three arguments as follows:
413 *
414 * arg0:
415 * bit[0-7] : sr_idle
416 * bit[8-15] : sr_mc_gate_idle
417 * bit[16-31] : standby idle
418 * arg1:
419 * bit[0-11] : pd_idle
420 * bit[16-27] : srpd_lite_idle
421 * arg2:
422 * bit[0] : odt enable
423 */
424 data->odt_pd_arg0 = (data->timing.sr_idle & 0xff) |
425 ((data->timing.sr_mc_gate_idle & 0xff) << 8) |
426 ((data->timing.standby_idle & 0xffff) << 16);
427 data->odt_pd_arg1 = (data->timing.pd_idle & 0xfff) |
428 ((data->timing.srpd_lite_idle & 0xfff) << 16);
429
430 /*
362 * We add a devfreq driver to our parent since it has a device tree node 431 * We add a devfreq driver to our parent since it has a device tree node
363 * with operating points. 432 * with operating points.
364 */ 433 */
diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h
index 7e28092c4d3d..ad9482c56797 100644
--- a/include/soc/rockchip/rockchip_sip.h
+++ b/include/soc/rockchip/rockchip_sip.h
@@ -23,5 +23,6 @@
23#define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE 0x05 23#define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE 0x05
24#define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06 24#define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06
25#define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07 25#define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07
26#define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD 0x08
26 27
27#endif 28#endif