drivers/devfreq/rk3399_dmc.c

Source file repositories/reference/linux-study-clean/drivers/devfreq/rk3399_dmc.c

File Facts

System
Linux kernel
Corpus path
drivers/devfreq/rk3399_dmc.c
Extension
.c
Size
13643 bytes
Lines
489
Domain
Driver Families
Bucket
drivers/devfreq
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct rk3399_dmcfreq {
	struct device *dev;
	struct devfreq *devfreq;
	struct devfreq_dev_profile profile;
	struct devfreq_simple_ondemand_data ondemand_data;
	struct clk *dmc_clk;
	struct devfreq_event_dev *edev;
	struct mutex lock;
	struct regulator *vdd_center;
	struct regmap *regmap_pmu;
	unsigned long rate, target_rate;
	unsigned long volt, target_volt;
	unsigned int odt_dis_freq;

	unsigned int pd_idle_ns;
	unsigned int sr_idle_ns;
	unsigned int sr_mc_gate_idle_ns;
	unsigned int srpd_lite_idle_ns;
	unsigned int standby_idle_ns;
	unsigned int ddr3_odt_dis_freq;
	unsigned int lpddr3_odt_dis_freq;
	unsigned int lpddr4_odt_dis_freq;

	unsigned int pd_idle_dis_freq;
	unsigned int sr_idle_dis_freq;
	unsigned int sr_mc_gate_idle_dis_freq;
	unsigned int srpd_lite_idle_dis_freq;
	unsigned int standby_idle_dis_freq;
};

static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
				 u32 flags)
{
	struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
	struct dev_pm_opp *opp;
	unsigned long old_clk_rate = dmcfreq->rate;
	unsigned long target_volt, target_rate;
	unsigned int ddrcon_mhz;
	struct arm_smccc_res res;
	int err;

	u32 odt_pd_arg0 = 0;
	u32 odt_pd_arg1 = 0;
	u32 odt_pd_arg2 = 0;

	opp = devfreq_recommended_opp(dev, freq, flags);
	if (IS_ERR(opp))
		return PTR_ERR(opp);

	target_rate = dev_pm_opp_get_freq(opp);
	target_volt = dev_pm_opp_get_voltage(opp);
	dev_pm_opp_put(opp);

	if (dmcfreq->rate == target_rate)
		return 0;

	mutex_lock(&dmcfreq->lock);

	/*
	 * Ensure power-domain transitions don't interfere with ARM Trusted
	 * Firmware power-domain idling.
	 */
	err = rockchip_pmu_block();
	if (err) {
		dev_err(dev, "Failed to block PMU: %d\n", err);
		goto out_unlock;
	}

	/*
	 * Some idle parameters may be based on the DDR controller clock, which
	 * is half of the DDR frequency.
	 * pd_idle and standby_idle are based on the controller clock cycle.
	 * sr_idle_cycle, sr_mc_gate_idle_cycle, and srpd_lite_idle_cycle
	 * are based on the 1024 controller clock cycle
	 */
	ddrcon_mhz = target_rate / USEC_PER_SEC / 2;

	u32p_replace_bits(&odt_pd_arg1,
			  NS_TO_CYCLE(dmcfreq->pd_idle_ns, ddrcon_mhz),
			  RK3399_SET_ODT_PD_1_PD_IDLE);
	u32p_replace_bits(&odt_pd_arg0,
			  NS_TO_CYCLE(dmcfreq->standby_idle_ns, ddrcon_mhz),
			  RK3399_SET_ODT_PD_0_STANDBY_IDLE);
	u32p_replace_bits(&odt_pd_arg0,
			  DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->sr_idle_ns,
						   ddrcon_mhz), 1024),
			  RK3399_SET_ODT_PD_0_SR_IDLE);
	u32p_replace_bits(&odt_pd_arg0,
			  DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->sr_mc_gate_idle_ns,
						   ddrcon_mhz), 1024),

Annotation

Implementation Notes