mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									adfe3b7660
								
							
						
					
					
						commit
						9173c5ceb0
					
				
					 2 changed files with 71 additions and 1 deletions
				
			
		| 
						 | 
					@ -18,14 +18,17 @@
 | 
				
			||||||
#include <linux/devfreq.h>
 | 
					#include <linux/devfreq.h>
 | 
				
			||||||
#include <linux/devfreq-event.h>
 | 
					#include <linux/devfreq-event.h>
 | 
				
			||||||
#include <linux/interrupt.h>
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/mfd/syscon.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/of.h>
 | 
					#include <linux/of.h>
 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
#include <linux/pm_opp.h>
 | 
					#include <linux/pm_opp.h>
 | 
				
			||||||
 | 
					#include <linux/regmap.h>
 | 
				
			||||||
#include <linux/regulator/consumer.h>
 | 
					#include <linux/regulator/consumer.h>
 | 
				
			||||||
#include <linux/rwsem.h>
 | 
					#include <linux/rwsem.h>
 | 
				
			||||||
#include <linux/suspend.h>
 | 
					#include <linux/suspend.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <soc/rockchip/rk3399_grf.h>
 | 
				
			||||||
#include <soc/rockchip/rockchip_sip.h>
 | 
					#include <soc/rockchip/rockchip_sip.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dram_timing {
 | 
					struct dram_timing {
 | 
				
			||||||
| 
						 | 
					@ -69,8 +72,11 @@ struct rk3399_dmcfreq {
 | 
				
			||||||
	struct mutex lock;
 | 
						struct mutex lock;
 | 
				
			||||||
	struct dram_timing timing;
 | 
						struct dram_timing timing;
 | 
				
			||||||
	struct regulator *vdd_center;
 | 
						struct regulator *vdd_center;
 | 
				
			||||||
 | 
						struct regmap *regmap_pmu;
 | 
				
			||||||
	unsigned long rate, target_rate;
 | 
						unsigned long rate, target_rate;
 | 
				
			||||||
	unsigned long volt, target_volt;
 | 
						unsigned long volt, target_volt;
 | 
				
			||||||
 | 
						unsigned int odt_dis_freq;
 | 
				
			||||||
 | 
						int odt_pd_arg0, odt_pd_arg1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
 | 
					static 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,
 | 
				
			||||||
	struct dev_pm_opp *opp;
 | 
						struct dev_pm_opp *opp;
 | 
				
			||||||
	unsigned long old_clk_rate = dmcfreq->rate;
 | 
						unsigned long old_clk_rate = dmcfreq->rate;
 | 
				
			||||||
	unsigned long target_volt, target_rate;
 | 
						unsigned long target_volt, target_rate;
 | 
				
			||||||
 | 
						struct arm_smccc_res res;
 | 
				
			||||||
 | 
						bool odt_enable = false;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opp = devfreq_recommended_opp(dev, freq, flags);
 | 
						opp = devfreq_recommended_opp(dev, freq, flags);
 | 
				
			||||||
| 
						 | 
					@ -95,6 +103,19 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&dmcfreq->lock);
 | 
						mutex_lock(&dmcfreq->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (target_rate >= dmcfreq->odt_dis_freq)
 | 
				
			||||||
 | 
							odt_enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * This makes a SMC call to the TF-A to set the DDR PD (power-down)
 | 
				
			||||||
 | 
						 * timings and to enable or disable the ODT (on-die termination)
 | 
				
			||||||
 | 
						 * resistors.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
 | 
				
			||||||
 | 
							      dmcfreq->odt_pd_arg1,
 | 
				
			||||||
 | 
							      ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
 | 
				
			||||||
 | 
							      odt_enable, 0, 0, 0, &res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If frequency scaling from low to high, adjust voltage first.
 | 
						 * If frequency scaling from low to high, adjust voltage first.
 | 
				
			||||||
	 * If frequency scaling from high to low, adjust frequency first.
 | 
						 * If frequency scaling from high to low, adjust frequency first.
 | 
				
			||||||
| 
						 | 
					@ -294,11 +315,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct arm_smccc_res res;
 | 
						struct arm_smccc_res res;
 | 
				
			||||||
	struct device *dev = &pdev->dev;
 | 
						struct device *dev = &pdev->dev;
 | 
				
			||||||
	struct device_node *np = pdev->dev.of_node;
 | 
						struct device_node *np = pdev->dev.of_node, *node;
 | 
				
			||||||
	struct rk3399_dmcfreq *data;
 | 
						struct rk3399_dmcfreq *data;
 | 
				
			||||||
	int ret, index, size;
 | 
						int ret, index, size;
 | 
				
			||||||
	uint32_t *timing;
 | 
						uint32_t *timing;
 | 
				
			||||||
	struct dev_pm_opp *opp;
 | 
						struct dev_pm_opp *opp;
 | 
				
			||||||
 | 
						u32 ddr_type;
 | 
				
			||||||
 | 
						u32 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
 | 
						data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
 | 
				
			||||||
	if (!data)
 | 
						if (!data)
 | 
				
			||||||
| 
						 | 
					@ -354,10 +377,56 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						node = of_parse_phandle(np, "rockchip,pmu", 0);
 | 
				
			||||||
 | 
						if (node) {
 | 
				
			||||||
 | 
							data->regmap_pmu = syscon_node_to_regmap(node);
 | 
				
			||||||
 | 
							if (IS_ERR(data->regmap_pmu))
 | 
				
			||||||
 | 
								return PTR_ERR(data->regmap_pmu);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
 | 
				
			||||||
 | 
						ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) &
 | 
				
			||||||
 | 
							    RK3399_PMUGRF_DDRTYPE_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ddr_type) {
 | 
				
			||||||
 | 
						case RK3399_PMUGRF_DDRTYPE_DDR3:
 | 
				
			||||||
 | 
							data->odt_dis_freq = data->timing.ddr3_odt_dis_freq;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case RK3399_PMUGRF_DDRTYPE_LPDDR3:
 | 
				
			||||||
 | 
							data->odt_dis_freq = data->timing.lpddr3_odt_dis_freq;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case RK3399_PMUGRF_DDRTYPE_LPDDR4:
 | 
				
			||||||
 | 
							data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
 | 
						arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
 | 
				
			||||||
		      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
 | 
							      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
 | 
				
			||||||
		      0, 0, 0, 0, &res);
 | 
							      0, 0, 0, 0, &res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * In TF-A there is a platform SIP call to set the PD (power-down)
 | 
				
			||||||
 | 
						 * timings and to enable or disable the ODT (on-die termination).
 | 
				
			||||||
 | 
						 * This call needs three arguments as follows:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * arg0:
 | 
				
			||||||
 | 
						 *     bit[0-7]   : sr_idle
 | 
				
			||||||
 | 
						 *     bit[8-15]  : sr_mc_gate_idle
 | 
				
			||||||
 | 
						 *     bit[16-31] : standby idle
 | 
				
			||||||
 | 
						 * arg1:
 | 
				
			||||||
 | 
						 *     bit[0-11]  : pd_idle
 | 
				
			||||||
 | 
						 *     bit[16-27] : srpd_lite_idle
 | 
				
			||||||
 | 
						 * arg2:
 | 
				
			||||||
 | 
						 *     bit[0]     : odt enable
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						data->odt_pd_arg0 = (data->timing.sr_idle & 0xff) |
 | 
				
			||||||
 | 
								    ((data->timing.sr_mc_gate_idle & 0xff) << 8) |
 | 
				
			||||||
 | 
								    ((data->timing.standby_idle & 0xffff) << 16);
 | 
				
			||||||
 | 
						data->odt_pd_arg1 = (data->timing.pd_idle & 0xfff) |
 | 
				
			||||||
 | 
								    ((data->timing.srpd_lite_idle & 0xfff) << 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We add a devfreq driver to our parent since it has a device tree node
 | 
						 * We add a devfreq driver to our parent since it has a device tree node
 | 
				
			||||||
	 * with operating points.
 | 
						 * with operating points.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,5 +23,6 @@
 | 
				
			||||||
#define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE	0x05
 | 
					#define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE	0x05
 | 
				
			||||||
#define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ	0x06
 | 
					#define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ	0x06
 | 
				
			||||||
#define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM	0x07
 | 
					#define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM	0x07
 | 
				
			||||||
 | 
					#define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD	0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue