예제 #1
0
static int a6xx_gmu_build_freq_table(struct device *dev, unsigned long *freqs,
		u32 size)
{
	int count = dev_pm_opp_get_opp_count(dev);
	struct dev_pm_opp *opp;
	int i, index = 0;
	unsigned long freq = 1;

	/*
	 * The OPP table doesn't contain the "off" frequency level so we need to
	 * add 1 to the table size to account for it
	 */

	if (WARN(count + 1 > size,
		"The GMU frequency table is being truncated\n"))
		count = size - 1;

	/* Set the "off" frequency */
	freqs[index++] = 0;

	for (i = 0; i < count; i++) {
		opp = dev_pm_opp_find_freq_ceil(dev, &freq);
		if (IS_ERR(opp))
			break;

		dev_pm_opp_put(opp);
		freqs[index++] = freq++;
	}

	return index;
}
예제 #2
0
/**
 * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
 * @dev:	device for which we do this operation
 * @table:	Cpufreq table returned back to caller
 *
 * Generate a cpufreq table for a provided device- this assumes that the
 * opp list is already initialized and ready for usage.
 *
 * This function allocates required memory for the cpufreq table. It is
 * expected that the caller does the required maintenance such as freeing
 * the table as required.
 *
 * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
 * if no memory available for the operation (table is not populated), returns 0
 * if successful and table is populated.
 *
 * WARNING: It is  important for the callers to ensure refreshing their copy of
 * the table if any of the mentioned functions have been invoked in the interim.
 *
 * Locking: The internal device_opp and opp structures are RCU protected.
 * Since we just use the regular accessor functions to access the internal data
 * structures, we use RCU read lock inside this function. As a result, users of
 * this function DONOT need to use explicit locks for invoking.
 */
int dev_pm_opp_init_cpufreq_table(struct device *dev,
				  struct cpufreq_frequency_table **table)
{
	struct dev_pm_opp *opp;
	struct cpufreq_frequency_table *freq_table = NULL;
	int i, max_opps, ret = 0;
	unsigned long rate;

	rcu_read_lock();

	max_opps = dev_pm_opp_get_opp_count(dev);
	if (max_opps <= 0) {
		ret = max_opps ? max_opps : -ENODATA;
		goto out;
	}

	freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
	if (!freq_table) {
		ret = -ENOMEM;
		goto out;
	}

	for (i = 0, rate = 0; i < max_opps; i++, rate++) {
		/* find next rate */
		opp = dev_pm_opp_find_freq_ceil(dev, &rate);
		if (IS_ERR(opp)) {
			ret = PTR_ERR(opp);
			goto out;
		}
		freq_table[i].driver_data = i;
		freq_table[i].frequency = rate / 1000;

		/* Is Boost/turbo opp ? */
		if (dev_pm_opp_is_turbo(opp))
			freq_table[i].flags = CPUFREQ_BOOST_FREQ;
	}

	freq_table[i].driver_data = i;
	freq_table[i].frequency = CPUFREQ_TABLE_END;

	*table = &freq_table[0];

out:
	rcu_read_unlock();
	if (ret)
		kfree(freq_table);

	return ret;
}
static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev,
		struct devfreq_dev_profile *dp)
{
	int count;
	int i = 0;
	unsigned long freq = 0;
	struct dev_pm_opp *opp;

	rcu_read_lock();
	count = dev_pm_opp_get_opp_count(kbdev->dev);
	if (count < 0) {
		rcu_read_unlock();
		return count;
	}
	rcu_read_unlock();

	dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]),
				GFP_KERNEL);
	if (!dp->freq_table)
		return -ENOMEM;

	rcu_read_lock();
	for (i = 0; i < count; i++, freq++) {
		opp = dev_pm_opp_find_freq_ceil(kbdev->dev, &freq);
		if (IS_ERR(opp))
			break;

		dp->freq_table[i] = freq;
	}
	rcu_read_unlock();

	if (count != i)
		dev_warn(kbdev->dev, "Unable to enumerate all OPPs (%d!=%d\n",
				count, i);

	dp->max_state = i;

	return 0;
}
예제 #4
0
static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
{
    struct device *cpu_dev;
    struct regulator *proc_reg = ERR_PTR(-ENODEV);
    struct regulator *sram_reg = ERR_PTR(-ENODEV);
    struct clk *cpu_clk = ERR_PTR(-ENODEV);
    struct clk *inter_clk = ERR_PTR(-ENODEV);
    struct dev_pm_opp *opp;
    unsigned long rate;
    int ret;

    cpu_dev = get_cpu_device(cpu);
    if (!cpu_dev) {
        pr_err("failed to get cpu%d device\n", cpu);
        return -ENODEV;
    }

    cpu_clk = clk_get(cpu_dev, "cpu");
    if (IS_ERR(cpu_clk)) {
        if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
            pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
        else
            pr_err("failed to get cpu clk for cpu%d\n", cpu);

        ret = PTR_ERR(cpu_clk);
        return ret;
    }

    inter_clk = clk_get(cpu_dev, "intermediate");
    if (IS_ERR(inter_clk)) {
        if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
            pr_warn("intermediate clk for cpu%d not ready, retry.\n",
                    cpu);
        else
            pr_err("failed to get intermediate clk for cpu%d\n",
                   cpu);

        ret = PTR_ERR(inter_clk);
        goto out_free_resources;
    }

    proc_reg = regulator_get_exclusive(cpu_dev, "proc");
    if (IS_ERR(proc_reg)) {
        if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
            pr_warn("proc regulator for cpu%d not ready, retry.\n",
                    cpu);
        else
            pr_err("failed to get proc regulator for cpu%d\n",
                   cpu);

        ret = PTR_ERR(proc_reg);
        goto out_free_resources;
    }

    /* Both presence and absence of sram regulator are valid cases. */
    sram_reg = regulator_get_exclusive(cpu_dev, "sram");

    ret = dev_pm_opp_of_add_table(cpu_dev);
    if (ret) {
        pr_warn("no OPP table for cpu%d\n", cpu);
        goto out_free_resources;
    }

    /* Search a safe voltage for intermediate frequency. */
    rate = clk_get_rate(inter_clk);
    rcu_read_lock();
    opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
    if (IS_ERR(opp)) {
        rcu_read_unlock();
        pr_err("failed to get intermediate opp for cpu%d\n", cpu);
        ret = PTR_ERR(opp);
        goto out_free_opp_table;
    }
    info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
    rcu_read_unlock();

    info->cpu_dev = cpu_dev;
    info->proc_reg = proc_reg;
    info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
    info->cpu_clk = cpu_clk;
    info->inter_clk = inter_clk;

    /*
     * If SRAM regulator is present, software "voltage tracking" is needed
     * for this CPU power domain.
     */
    info->need_voltage_tracking = !IS_ERR(sram_reg);

    return 0;

out_free_opp_table:
    dev_pm_opp_of_remove_table(cpu_dev);

out_free_resources:
    if (!IS_ERR(proc_reg))
        regulator_put(proc_reg);
    if (!IS_ERR(sram_reg))
        regulator_put(sram_reg);
    if (!IS_ERR(cpu_clk))
        clk_put(cpu_clk);
    if (!IS_ERR(inter_clk))
        clk_put(inter_clk);

    return ret;
}
예제 #5
0
static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
                                  unsigned int index)
{
    struct cpufreq_frequency_table *freq_table = policy->freq_table;
    struct clk *cpu_clk = policy->clk;
    struct clk *armpll = clk_get_parent(cpu_clk);
    struct mtk_cpu_dvfs_info *info = policy->driver_data;
    struct device *cpu_dev = info->cpu_dev;
    struct dev_pm_opp *opp;
    long freq_hz, old_freq_hz;
    int vproc, old_vproc, inter_vproc, target_vproc, ret;

    inter_vproc = info->intermediate_voltage;

    old_freq_hz = clk_get_rate(cpu_clk);
    old_vproc = regulator_get_voltage(info->proc_reg);

    freq_hz = freq_table[index].frequency * 1000;

    rcu_read_lock();
    opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
    if (IS_ERR(opp)) {
        rcu_read_unlock();
        pr_err("cpu%d: failed to find OPP for %ld\n",
               policy->cpu, freq_hz);
        return PTR_ERR(opp);
    }
    vproc = dev_pm_opp_get_voltage(opp);
    rcu_read_unlock();

    /*
     * If the new voltage or the intermediate voltage is higher than the
     * current voltage, scale up voltage first.
     */
    target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
    if (old_vproc < target_vproc) {
        ret = mtk_cpufreq_set_voltage(info, target_vproc);
        if (ret) {
            pr_err("cpu%d: failed to scale up voltage!\n",
                   policy->cpu);
            mtk_cpufreq_set_voltage(info, old_vproc);
            return ret;
        }
    }

    /* Reparent the CPU clock to intermediate clock. */
    ret = clk_set_parent(cpu_clk, info->inter_clk);
    if (ret) {
        pr_err("cpu%d: failed to re-parent cpu clock!\n",
               policy->cpu);
        mtk_cpufreq_set_voltage(info, old_vproc);
        WARN_ON(1);
        return ret;
    }

    /* Set the original PLL to target rate. */
    ret = clk_set_rate(armpll, freq_hz);
    if (ret) {
        pr_err("cpu%d: failed to scale cpu clock rate!\n",
               policy->cpu);
        clk_set_parent(cpu_clk, armpll);
        mtk_cpufreq_set_voltage(info, old_vproc);
        return ret;
    }

    /* Set parent of CPU clock back to the original PLL. */
    ret = clk_set_parent(cpu_clk, armpll);
    if (ret) {
        pr_err("cpu%d: failed to re-parent cpu clock!\n",
               policy->cpu);
        mtk_cpufreq_set_voltage(info, inter_vproc);
        WARN_ON(1);
        return ret;
    }

    /*
     * If the new voltage is lower than the intermediate voltage or the
     * original voltage, scale down to the new voltage.
     */
    if (vproc < inter_vproc || vproc < old_vproc) {
        ret = mtk_cpufreq_set_voltage(info, vproc);
        if (ret) {
            pr_err("cpu%d: failed to scale down voltage!\n",
                   policy->cpu);
            clk_set_parent(cpu_clk, info->inter_clk);
            clk_set_rate(armpll, old_freq_hz);
            clk_set_parent(cpu_clk, armpll);
            return ret;
        }
    }

    return 0;
}
예제 #6
0
static int imx7d_set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
	unsigned long freq_hz, volt, volt_old;
	unsigned int old_freq, new_freq;
	int ret;

	mutex_lock(&set_cpufreq_lock);

	new_freq = freq_table[index].frequency;
	freq_hz = new_freq * 1000;
	old_freq = clk_get_rate(arm_clk) / 1000;

	rcu_read_lock();
	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
	if (IS_ERR(opp)) {
		rcu_read_unlock();
		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
		mutex_unlock(&set_cpufreq_lock);
		return PTR_ERR(opp);
	}
	volt = dev_pm_opp_get_voltage(opp);

	rcu_read_unlock();
	volt_old = regulator_get_voltage(arm_reg);

	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
		old_freq / 1000, volt_old / 1000,
		new_freq / 1000, volt / 1000);

	/* Scaling up? scale voltage before frequency */
	if (new_freq > old_freq) {
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret);
			mutex_unlock(&set_cpufreq_lock);
			return ret;
		}
	}

	/* before changing pll_arm rate, change the arm_src's soure
	 * to pll_sys_main clk first.
	 */
	clk_set_parent(arm_src, pll_sys_main);
	clk_set_rate(pll_arm, new_freq * 1000);
	clk_set_parent(arm_src, pll_arm);

	/* change the cpu frequency */
	ret = clk_set_rate(arm_clk, new_freq * 1000);
	if (ret) {
		dev_err(cpu_dev, " failed to set clock rate: %d\n", ret);
		regulator_set_voltage_tol(arm_reg, volt_old, 0);
		mutex_unlock(&set_cpufreq_lock);
		return ret;
	}

	/* scaling down? scaling voltage after frequency */
	if (new_freq < old_freq) {
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret);
			ret = 0;
		}
	}

	mutex_unlock(&set_cpufreq_lock);
	return 0;
}
예제 #7
0
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
	unsigned long freq_hz, volt, volt_old;
	unsigned int old_freq, new_freq;
	bool pll1_sys_temp_enabled = false;
	int ret;

	new_freq = freq_table[index].frequency;
	freq_hz = new_freq * 1000;
	old_freq = clk_get_rate(arm_clk) / 1000;

	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
	if (IS_ERR(opp)) {
		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
		return PTR_ERR(opp);
	}

	volt = dev_pm_opp_get_voltage(opp);
	dev_pm_opp_put(opp);

	volt_old = regulator_get_voltage(arm_reg);

	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
		old_freq / 1000, volt_old / 1000,
		new_freq / 1000, volt / 1000);

	/* scaling up?  scale voltage before frequency */
	if (new_freq > old_freq) {
		if (!IS_ERR(pu_reg)) {
			ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
			if (ret) {
				dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);
				return ret;
			}
		}
		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
		if (ret) {
			dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);
			return ret;
		}
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_err(cpu_dev,
				"failed to scale vddarm up: %d\n", ret);
			return ret;
		}
	}

	/*
	 * The setpoints are selected per PLL/PDF frequencies, so we need to
	 * reprogram PLL for frequency scaling.  The procedure of reprogramming
	 * PLL1 is as below.
	 * For i.MX6UL, it has a secondary clk mux, the cpu frequency change
	 * flow is slightly different from other i.MX6 OSC.
	 * The cpu frequeny change flow for i.MX6(except i.MX6UL) is as below:
	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
	 *  - Disable pll2_pfd2_396m_clk
	 */
	if (of_machine_is_compatible("fsl,imx6ul") ||
	    of_machine_is_compatible("fsl,imx6ull")) {
		/*
		 * When changing pll1_sw_clk's parent to pll1_sys_clk,
		 * CPU may run at higher than 528MHz, this will lead to
		 * the system unstable if the voltage is lower than the
		 * voltage of 528MHz, so lower the CPU frequency to one
		 * half before changing CPU frequency.
		 */
		clk_set_rate(arm_clk, (old_freq >> 1) * 1000);
		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
		if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk))
			clk_set_parent(secondary_sel_clk, pll2_bus_clk);
		else
			clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk);
		clk_set_parent(step_clk, secondary_sel_clk);
		clk_set_parent(pll1_sw_clk, step_clk);
	} else {
예제 #8
0
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
	unsigned long freq_hz, volt, volt_old;
	unsigned int old_freq, new_freq;
	int ret;

	mutex_lock(&set_cpufreq_lock);

	new_freq = freq_table[index].frequency;
	freq_hz = new_freq * 1000;
	old_freq = clk_get_rate(arm_clk) / 1000;

	rcu_read_lock();
	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
	if (IS_ERR(opp)) {
		rcu_read_unlock();
		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
		mutex_unlock(&set_cpufreq_lock);
		return PTR_ERR(opp);
	}

	volt = dev_pm_opp_get_voltage(opp);
	rcu_read_unlock();
	volt_old = regulator_get_voltage(arm_reg);

	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
		old_freq / 1000, volt_old / 1000,
		new_freq / 1000, volt / 1000);
	/*
	 * CPU freq is increasing, so need to ensure
	 * that bus frequency is increased too.
	 */
	if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ)
		request_bus_freq(BUS_FREQ_HIGH);

	/* scaling up?  scale voltage before frequency */
	if (new_freq > old_freq) {
		if (!IS_ERR(pu_reg)) {
			ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
			if (ret) {
				dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);
				mutex_unlock(&set_cpufreq_lock);
				return ret;
			}
		}
		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
		if (ret) {
			dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);
			mutex_unlock(&set_cpufreq_lock);
			return ret;
		}
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_err(cpu_dev,
				"failed to scale vddarm up: %d\n", ret);
			mutex_unlock(&set_cpufreq_lock);
			return ret;
		}
	}

	/*
	 * The setpoints are selected per PLL/PDF frequencies, so we need to
	 * reprogram PLL for frequency scaling. The procedure of reprogramming
	 * PLL1 is as below.
	 * For i.MX6UL, it has a secondary clk mux, the cpu frequency change
	 * flow is slightly different from other I.MX6 SOC.
	 *
	 * The cpu frequency change flow for i.MX6(except i.MX6UL) is as below:
	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
	 *  - Disable pll2_pfd2_396m_clk
	 */
	if (!IS_ERR(secondary_sel)) {

		/* When changing pll1_sw source to pll1_sys, cpu may run at higher
		 * than 528MHz, this will lead to the system unstable if the voltage
		 * is lower than the voltage of 528MHz. So lower the cpu frequency to
		 * one half before changing cpu frequency.
		 */
		clk_set_rate(arm_clk, (old_freq >> 1) * 1000);
		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
		clk_set_parent(step_clk, osc);
		if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk))
			clk_set_parent(secondary_sel, pll2_bus);
		else
			clk_set_parent(secondary_sel, pll2_pfd2_396m_clk);
		clk_set_parent(step_clk, secondary_sel);
		clk_set_parent(pll1_sw_clk, step_clk);
		if (freq_hz > clk_get_rate(pll2_bus)) {
			clk_set_rate(pll1, new_freq * 1000);
			clk_set_parent(pll1_sw_clk, pll1_sys_clk);
		}
	} else {
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
	unsigned long freq_hz, volt, volt_old;
	unsigned int old_freq, new_freq;
	int ret;

	new_freq = freq_table[index].frequency;
	freq_hz = new_freq * 1000;
	old_freq = clk_get_rate(arm_clk) / 1000;

	rcu_read_lock();
	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
	if (IS_ERR(opp)) {
		rcu_read_unlock();
		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
		return PTR_ERR(opp);
	}

	volt = dev_pm_opp_get_voltage(opp);
	rcu_read_unlock();
	volt_old = regulator_get_voltage(arm_reg);

	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
		old_freq / 1000, volt_old / 1000,
		new_freq / 1000, volt / 1000);

	/* scaling up?  scale voltage before frequency */
	if (new_freq > old_freq) {
		if (!IS_ERR(pu_reg)) {
			ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
			if (ret) {
				dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);
				return ret;
			}
		}
		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
		if (ret) {
			dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);
			return ret;
		}
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_err(cpu_dev,
				"failed to scale vddarm up: %d\n", ret);
			return ret;
		}
	}

	/*
	 * The setpoints are selected per PLL/PDF frequencies, so we need to
	 * reprogram PLL for frequency scaling.  The procedure of reprogramming
	 * PLL1 is as below.
	 *
	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
	 *  - Disable pll2_pfd2_396m_clk
	 */
	clk_set_parent(step_clk, pll2_pfd2_396m_clk);
	clk_set_parent(pll1_sw_clk, step_clk);
	if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
		clk_set_rate(pll1_sys_clk, new_freq * 1000);
		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
	}

	/* Ensure the arm clock divider is what we expect */
	ret = clk_set_rate(arm_clk, new_freq * 1000);
	if (ret) {
		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
		regulator_set_voltage_tol(arm_reg, volt_old, 0);
		return ret;
	}

	/* scaling down?  scale voltage after frequency */
	if (new_freq < old_freq) {
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_warn(cpu_dev,
				 "failed to scale vddarm down: %d\n", ret);
			ret = 0;
		}
		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
		if (ret) {
			dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret);
			ret = 0;
		}
		if (!IS_ERR(pu_reg)) {
			ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
			if (ret) {
				dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret);
				ret = 0;
			}
		}
	}

	return 0;
}
예제 #10
0
static int set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
	struct cpufreq_frequency_table *freq_table = policy->freq_table;
	struct clk *cpu_clk = policy->clk;
	struct private_data *priv = policy->driver_data;
	struct device *cpu_dev = priv->cpu_dev;
	struct regulator *cpu_reg = priv->cpu_reg;
	unsigned long volt = 0, volt_old = 0, tol = 0;
	unsigned int old_freq, new_freq;
	long freq_Hz, freq_exact;
	int ret;

	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
	if (freq_Hz <= 0)
		freq_Hz = freq_table[index].frequency * 1000;

	freq_exact = freq_Hz;
	new_freq = freq_Hz / 1000;
	old_freq = clk_get_rate(cpu_clk) / 1000;

	if (!IS_ERR(cpu_reg)) {
		rcu_read_lock();
		opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
		if (IS_ERR(opp)) {
			rcu_read_unlock();
			dev_err(cpu_dev, "failed to find OPP for %ld\n",
				freq_Hz);
			return PTR_ERR(opp);
		}
		volt = dev_pm_opp_get_voltage(opp);
		rcu_read_unlock();
		tol = volt * priv->voltage_tolerance / 100;
		volt_old = regulator_get_voltage(cpu_reg);
	}

	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
		old_freq / 1000, volt_old ? volt_old / 1000 : -1,
		new_freq / 1000, volt ? volt / 1000 : -1);

	/* scaling up?  scale voltage before frequency */
	if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
		if (ret) {
			dev_err(cpu_dev, "failed to scale voltage up: %d\n",
				ret);
			return ret;
		}
	}

	ret = clk_set_rate(cpu_clk, freq_exact);
	if (ret) {
		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
		if (!IS_ERR(cpu_reg))
			regulator_set_voltage_tol(cpu_reg, volt_old, tol);
		return ret;
	}

	/* scaling down?  scale voltage after frequency */
	if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
		if (ret) {
			dev_err(cpu_dev, "failed to scale voltage down: %d\n",
				ret);
			clk_set_rate(cpu_clk, old_freq * 1000);
		}
	}

	return ret;
}
예제 #11
0
static int cpufreq_init(struct cpufreq_policy *policy)
{
	struct cpufreq_dt_platform_data *pd;
	struct cpufreq_frequency_table *freq_table;
	struct thermal_cooling_device *cdev;
	struct device_node *np;
	struct private_data *priv;
	struct device *cpu_dev;
	struct regulator *cpu_reg;
	struct clk *cpu_clk;
	unsigned long min_uV = ~0, max_uV = 0;
	unsigned int transition_latency;
	int ret;

	ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk);
	if (ret) {
		pr_err("%s: Failed to allocate resources\n: %d", __func__, ret);
		return ret;
	}

	np = of_node_get(cpu_dev->of_node);
	if (!np) {
		dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu);
		ret = -ENOENT;
		goto out_put_reg_clk;
	}

	/* OPPs might be populated at runtime, don't check for error here */
	of_init_opp_table(cpu_dev);

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto out_put_node;
	}

	of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);

	if (of_property_read_u32(np, "clock-latency", &transition_latency))
		transition_latency = CPUFREQ_ETERNAL;

	if (!IS_ERR(cpu_reg)) {
		unsigned long opp_freq = 0;

		/*
		 * Disable any OPPs where the connected regulator isn't able to
		 * provide the specified voltage and record minimum and maximum
		 * voltage levels.
		 */
		while (1) {
			struct dev_pm_opp *opp;
			unsigned long opp_uV, tol_uV;

			rcu_read_lock();
			opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq);
			if (IS_ERR(opp)) {
				rcu_read_unlock();
				break;
			}
			opp_uV = dev_pm_opp_get_voltage(opp);
			rcu_read_unlock();

			tol_uV = opp_uV * priv->voltage_tolerance / 100;
			if (regulator_is_supported_voltage(cpu_reg, opp_uV,
							   opp_uV + tol_uV)) {
				if (opp_uV < min_uV)
					min_uV = opp_uV;
				if (opp_uV > max_uV)
					max_uV = opp_uV;
			} else {
				dev_pm_opp_disable(cpu_dev, opp_freq);
			}

			opp_freq++;
		}

		ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
		if (ret > 0)
			transition_latency += ret * 1000;
	}

	ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
	if (ret) {
		pr_err("failed to init cpufreq table: %d\n", ret);
		goto out_free_priv;
	}

	/*
	 * For now, just loading the cooling device;
	 * thermal DT code takes care of matching them.
	 */
	if (of_find_property(np, "#cooling-cells", NULL)) {
		cdev = of_cpufreq_cooling_register(np, cpu_present_mask);
		if (IS_ERR(cdev))
			dev_err(cpu_dev,
				"running cpufreq without cooling device: %ld\n",
				PTR_ERR(cdev));
		else
			priv->cdev = cdev;
	}

	priv->cpu_dev = cpu_dev;
	priv->cpu_reg = cpu_reg;
	policy->driver_data = priv;

	policy->clk = cpu_clk;
	ret = cpufreq_table_validate_and_show(policy, freq_table);
	if (ret) {
		dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__,
			ret);
		goto out_cooling_unregister;
	}

	policy->cpuinfo.transition_latency = transition_latency;

	pd = cpufreq_get_driver_data();
	if (!pd || !pd->independent_clocks)
		cpumask_setall(policy->cpus);

	of_node_put(np);

	return 0;

out_cooling_unregister:
	cpufreq_cooling_unregister(priv->cdev);
	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_priv:
	kfree(priv);
out_put_node:
	of_node_put(np);
out_put_reg_clk:
	clk_put(cpu_clk);
	if (!IS_ERR(cpu_reg))
		regulator_put(cpu_reg);

	return ret;
}
예제 #12
0
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{
	struct dev_pm_opp *opp;
	unsigned long freq_hz, volt, volt_old;
	unsigned int old_freq, new_freq;
	int ret;

	mutex_lock(&set_cpufreq_lock);

	new_freq = freq_table[index].frequency;
	freq_hz = new_freq * 1000;
	old_freq = clk_get_rate(arm_clk) / 1000;

	rcu_read_lock();
	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
	if (IS_ERR(opp)) {
		rcu_read_unlock();
		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
		mutex_unlock(&set_cpufreq_lock);
		return PTR_ERR(opp);
	}

	volt = dev_pm_opp_get_voltage(opp);
	rcu_read_unlock();
	volt_old = regulator_get_voltage(arm_reg);

	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
		old_freq / 1000, volt_old / 1000,
		new_freq / 1000, volt / 1000);
	/*
	 * CPU freq is increasing, so need to ensure
	 * that bus frequency is increased too.
	 */
	if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ)
		request_bus_freq(BUS_FREQ_HIGH);

	/* scaling up?  scale voltage before frequency */
	if (new_freq > old_freq) {
		if (!IS_ERR(pu_reg) && regulator_is_enabled(pu_reg)) {
			ret = regulator_set_voltage_tol(pu_reg,
				imx6_soc_volt[index], 0);
			if (ret) {
				dev_err(cpu_dev,
					"failed to scale vddpu up: %d\n", ret);
				mutex_unlock(&set_cpufreq_lock);
				return ret;
			}
		}
		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
		if (ret) {
			dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);
			mutex_unlock(&set_cpufreq_lock);
			return ret;
		}
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_err(cpu_dev,
				"failed to scale vddarm up: %d\n", ret);
			mutex_unlock(&set_cpufreq_lock);
			return ret;
		}
	}

	/*
	 * The setpoints are selected per PLL/PDF frequencies, so we need to
	 * reprogram PLL for frequency scaling.  The procedure of reprogramming
	 * PLL1 is as below.
	 *
	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
	 *  - Disable pll2_pfd2_396m_clk
	 */
	clk_set_parent(step_clk, pll2_pfd2_396m_clk);
	clk_set_parent(pll1_sw_clk, step_clk);
	if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
		clk_set_rate(pll1, new_freq * 1000);
		/*
		  * Ensure pll1_bypass is set back to pll1.
		  */
		clk_set_parent(pll1_bypass, pll1);
		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
	} else
		/*
		  * Need to ensure that PLL1 is bypassed and enabled
		  * before ARM-PODF is set.
		  */
		clk_set_parent(pll1_bypass, pll1_bypass_src);


	/* Ensure the arm clock divider is what we expect */
	ret = clk_set_rate(arm_clk, new_freq * 1000);
	if (ret) {
		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
		regulator_set_voltage_tol(arm_reg, volt_old, 0);
		mutex_unlock(&set_cpufreq_lock);
		return ret;
	}

	/* scaling down?  scale voltage after frequency */
	if (new_freq < old_freq) {
		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
		if (ret) {
			dev_warn(cpu_dev,
				 "failed to scale vddarm down: %d\n", ret);
			ret = 0;
		}
		ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
		if (ret) {
			dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret);
			ret = 0;
		}
		if (!IS_ERR(pu_reg) && regulator_is_enabled(pu_reg)) {
			ret = regulator_set_voltage_tol(pu_reg,
				imx6_soc_volt[index], 0);
			if (ret) {
				dev_warn(cpu_dev,
					"failed to scale vddpu down: %d\n",
					ret);
				ret = 0;
			}
		}
	}
	/*
	 * If CPU is dropped to the lowest level, release the need
	 * for a high bus frequency.
	 */
	if (old_freq > FREQ_396_MHZ && new_freq <= FREQ_396_MHZ)
		release_bus_freq(BUS_FREQ_HIGH);

	mutex_unlock(&set_cpufreq_lock);
	return 0;
}
예제 #13
0
static int omap_target(struct cpufreq_policy *policy, unsigned int index)
{
	int r, ret;
	struct dev_pm_opp *opp;
	unsigned long freq, volt = 0, volt_old = 0, tol = 0;
	unsigned int old_freq, new_freq;

	old_freq = policy->cur;
	new_freq = freq_table[index].frequency;

	freq = new_freq * 1000;
	ret = clk_round_rate(policy->clk, freq);
	if (IS_ERR_VALUE(ret)) {
		dev_warn(mpu_dev,
			 "CPUfreq: Cannot find matching frequency for %lu\n",
			 freq);
		return ret;
	}
	freq = ret;

	if (mpu_reg) {
		rcu_read_lock();
		opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
		if (IS_ERR(opp)) {
			rcu_read_unlock();
			dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
				__func__, new_freq);
			return -EINVAL;
		}
		volt = dev_pm_opp_get_voltage(opp);
		rcu_read_unlock();
		tol = volt * OPP_TOLERANCE / 100;
		volt_old = regulator_get_voltage(mpu_reg);
	}

	dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", 
		old_freq / 1000, volt_old ? volt_old / 1000 : -1,
		new_freq / 1000, volt ? volt / 1000 : -1);

	/* scaling up?  scale voltage before frequency */
	if (mpu_reg && (new_freq > old_freq)) {
		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
		if (r < 0) {
			dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
				 __func__);
			return r;
		}
	}

	ret = clk_set_rate(policy->clk, new_freq * 1000);

	/* scaling down?  scale voltage after frequency */
	if (mpu_reg && (new_freq < old_freq)) {
		r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
		if (r < 0) {
			dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
				 __func__);
			clk_set_rate(policy->clk, old_freq * 1000);
			return r;
		}
	}

	return ret;
}