[PATCH 4/4] cpufreq: imx6q: correct VDDSOC/PU voltage scaling when cpufreq is changed

Shawn Guo shawn.guo at linaro.org
Tue Dec 17 02:02:21 EST 2013


On Tue, Dec 17, 2013 at 11:52:57AM -0500, Anson Huang wrote:
> > > @@ -63,29 +68,48 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
> > >  	rcu_read_unlock();
> > >  	volt_old = regulator_get_voltage(arm_reg);
> > >  
> > > -	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
> > > +	/* Find the matching VDDSOC/VDDPU operating voltage */
> > > +	while (soc_opp_index < soc_opp_count) {
> > > +		if (new_freq == imx6_soc_opp[soc_opp_index].arm_freq)
> > > +			break;
> > > +		soc_opp_index++;
> > > +	}
> > 
> > I'm not comfortable with this lookup every time imx6q_set_target() is
> > called.  I think we can use the 'index' variable to find VDDSOC/VDDPU
> > operating voltage from imx6_soc_opp table directly, if we sort the table
> > in the same order that freq_table is sorted.
> >
> 
> yes, we can use the index passed from OPP, then I will add some comments that
> the freq/volt table of vddsoc should be sorted in same order.

It's not as easy as adding some comments.  I think we need to ensure the
order in probe function, probably sorting them in code.  Otherwise, it's
dangerous if we're running at a frequency with a wrong voltage.

Also, if we sort the table in the same order as freq_table, we do not
even need to have arm_freq in the soc_opp table.

<snip>

> > > +	dev_dbg(cpu_dev, "%u MHz, arm %ld mV, soc-pu %d mV --> %u MHz, arm %ld mV, soc-pu %d mV\n",
> > >  		old_freq / 1000, volt_old / 1000,
> > > -		new_freq / 1000, volt / 1000);
> > > +		imx6_soc_opp[soc_opp_index].soc_volt / 1000,
> > > +		new_freq / 1000, volt / 1000,
> > > +		imx6_soc_opp[soc_opp_index].soc_volt / 1000);
> > 
> > You print the same soc_volt for both old and new ones?
> 
> this is my mistake, maybe I can leave the original code here to only
> print out vddarm's voltage? Otherwise, I have to add variable to keep
> old vddsoc/pu's voltage.

Yea, that's okay with leaving it as the existing code.

<snip>

> > > +	/*
> > > +	 * 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) {
> > > +		dev_err(cpu_dev, "Invalid fsl-soc-operating-points list!\n");
> > 
> > fsl,soc-operating-points
> > 
> > and
> > 
> > 		ret = -EINVAL;
> 
> no need to free freq table here?

We're only populating the error code here, and will still goto
free_freq_table below.

> > > +		goto free_freq_table;
> > > +	}

<snip>

> > > +	min_volt = max_volt = 0;
> > > +	for (i = 0; i < nr / 2; i++) {
> > > +		unsigned long freq = be32_to_cpup(val++);
> > > +		unsigned long volt = be32_to_cpup(val++);
> > > +
> > > +		if (i == 0)
> > > +			min_volt = max_volt = volt;
> > > +		if (volt < min_volt)
> > > +			min_volt = volt;
> > > +		if (volt > max_volt)
> > > +			max_volt = volt;
> > > +		opp = dev_pm_opp_find_freq_exact(cpu_dev, freq * 1000, true);
> > > +		imx6_soc_opp[i].arm_freq = freq;
> > > +		imx6_soc_opp[i].soc_volt = volt;
> > > +		soc_opp_count++;
> > > +	}
> > > +	rcu_read_unlock();
> > 
> > We may need another sanity check to see if soc_opp_count == num (arm opp
> > count) here.
> 
> yes, will add it, need to make sure soc_opp_count is same as arm opp count,
> but since we did NOT have 1G2 check, so the soc_opp_count will ">=" arm opp
> count.

Hmm, this is another problem with the for-loop above.  The soc_volt
should be added into imx6_soc_opp table and soc_opp_count increases,
only when dev_pm_opp_find_freq_exact() succeeds (IOW, the freq can be
found in arm opp table).

Shawn




More information about the linux-arm-kernel mailing list