Esempio n. 1
0
static int a6xx_gmu_pwrlevels_probe(struct a6xx_gmu *gmu)
{
	struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu);
	struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
	struct msm_gpu *gpu = &adreno_gpu->base;

	int ret = 0;

	/*
	 * The GMU handles its own frequency switching so build a list of
	 * available frequencies to send during initialization
	 */
	ret = dev_pm_opp_of_add_table(gmu->dev);
	if (ret) {
		DRM_DEV_ERROR(gmu->dev, "Unable to set the OPP table for the GMU\n");
		return ret;
	}

	gmu->nr_gmu_freqs = a6xx_gmu_build_freq_table(gmu->dev,
		gmu->gmu_freqs, ARRAY_SIZE(gmu->gmu_freqs));

	/*
	 * The GMU also handles GPU frequency switching so build a list
	 * from the GPU OPP table
	 */
	gmu->nr_gpu_freqs = a6xx_gmu_build_freq_table(&gpu->pdev->dev,
		gmu->gpu_freqs, ARRAY_SIZE(gmu->gpu_freqs));

	/* Build the list of RPMh votes that we'll send to the GMU */
	return a6xx_gmu_rpmh_votes_init(gmu);
}
Esempio n. 2
0
int panfrost_devfreq_init(struct panfrost_device *pfdev)
{
	int ret;
	struct dev_pm_opp *opp;

	if (!pfdev->regulator)
		return 0;

	ret = dev_pm_opp_of_add_table(&pfdev->pdev->dev);
	if (ret)
		return ret;

	panfrost_devfreq_reset(pfdev);

	pfdev->devfreq.cur_freq = clk_get_rate(pfdev->clock);

	opp = devfreq_recommended_opp(&pfdev->pdev->dev, &pfdev->devfreq.cur_freq, 0);
	if (IS_ERR(opp))
		return PTR_ERR(opp);

	panfrost_devfreq_profile.initial_freq = pfdev->devfreq.cur_freq;
	dev_pm_opp_put(opp);

	pfdev->devfreq.devfreq = devm_devfreq_add_device(&pfdev->pdev->dev,
			&panfrost_devfreq_profile, "simple_ondemand", NULL);
	if (IS_ERR(pfdev->devfreq.devfreq)) {
		DRM_DEV_ERROR(&pfdev->pdev->dev, "Couldn't initialize GPU devfreq\n");
		ret = PTR_ERR(pfdev->devfreq.devfreq);
		pfdev->devfreq.devfreq = NULL;
		return ret;
	}

	return 0;
}
Esempio n. 3
0
static int dt_init_opp_table(struct device *cpu_dev)
{
	struct device_node *np;
	int ret;

	np = of_node_get(cpu_dev->of_node);
	if (!np) {
		pr_err("failed to find cpu%d node\n", cpu_dev->id);
		return -ENOENT;
	}

	ret = dev_pm_opp_of_add_table(cpu_dev);
	of_node_put(np);

	return ret;
}
Esempio n. 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;
}
static int imx6q_cpufreq_probe(struct platform_device *pdev)
{
	struct device_node *np;
	struct dev_pm_opp *opp;
	unsigned long min_volt, max_volt;
	int num, ret;
	const struct property *prop;
	const __be32 *val;
	u32 nr, i, j;

	cpu_dev = get_cpu_device(0);
	if (!cpu_dev) {
		pr_err("failed to get cpu0 device\n");
		return -ENODEV;
	}

	np = of_node_get(cpu_dev->of_node);
	if (!np) {
		dev_err(cpu_dev, "failed to find cpu0 node\n");
		return -ENOENT;
	}

	arm_clk = clk_get(cpu_dev, "arm");
	pll1_sys_clk = clk_get(cpu_dev, "pll1_sys");
	pll1_sw_clk = clk_get(cpu_dev, "pll1_sw");
	step_clk = clk_get(cpu_dev, "step");
	pll2_pfd2_396m_clk = clk_get(cpu_dev, "pll2_pfd2_396m");
	if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
	    IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
		dev_err(cpu_dev, "failed to get clocks\n");
		ret = -ENOENT;
		goto put_clk;
	}

	arm_reg = regulator_get(cpu_dev, "arm");
	pu_reg = regulator_get_optional(cpu_dev, "pu");
	soc_reg = regulator_get(cpu_dev, "soc");
	if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) {
		dev_err(cpu_dev, "failed to get regulators\n");
		ret = -ENOENT;
		goto put_reg;
	}

	/*
	 * We expect an OPP table supplied by platform.
	 * Just, incase the platform did not supply the OPP
	 * table, it will try to get it.
	 */
	num = dev_pm_opp_get_opp_count(cpu_dev);
	if (num < 0) {
		ret = dev_pm_opp_of_add_table(cpu_dev);
		if (ret < 0) {
			dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
			goto put_reg;
		}

		/* Because we have added the OPPs here, we must free them */
		free_opp = true;

		num = dev_pm_opp_get_opp_count(cpu_dev);
		if (num < 0) {
			ret = num;
			dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
			goto out_free_opp;
		}
	}

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

	/* Make imx6_soc_volt array's size same as arm opp number */
	imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL);
	if (imx6_soc_volt == NULL) {
		ret = -ENOMEM;
		goto free_freq_table;
	}

	prop = of_find_property(np, "fsl,soc-operating-points", NULL);
	if (!prop || !prop->value)
		goto soc_opp_out;

	/*
	 * 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 || (nr / 2) < num)
		goto soc_opp_out;

	for (j = 0; j < num; j++) {
		val = prop->value;
		for (i = 0; i < nr / 2; i++) {
			unsigned long freq = be32_to_cpup(val++);
			unsigned long volt = be32_to_cpup(val++);
			if (freq_table[j].frequency == freq) {
				imx6_soc_volt[soc_opp_count++] = volt;
				break;
			}
		}
	}

soc_opp_out:
	/* use fixed soc opp volt if no valid soc opp info found in dtb */
	if (soc_opp_count != num) {
		dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value!\n");
		for (j = 0; j < num; j++)
			imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL;
		if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ)
			imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH;
	}

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

	/*
	 * Calculate the ramp time for max voltage change in the
	 * VDDSOC and VDDPU regulators.
	 */
	ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);
	if (ret > 0)
		transition_latency += ret * 1000;
	if (!IS_ERR(pu_reg)) {
		ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);
		if (ret > 0)
			transition_latency += ret * 1000;
	}

	/*
	 * OPP is maintained in order of increasing frequency, and
	 * freq_table initialised from OPP is therefore sorted in the
	 * same order.
	 */
	rcu_read_lock();
	opp = dev_pm_opp_find_freq_exact(cpu_dev,
				  freq_table[0].frequency * 1000, true);
	min_volt = dev_pm_opp_get_voltage(opp);
	opp = dev_pm_opp_find_freq_exact(cpu_dev,
				  freq_table[--num].frequency * 1000, true);
	max_volt = dev_pm_opp_get_voltage(opp);
	rcu_read_unlock();
	ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
	if (ret > 0)
		transition_latency += ret * 1000;

	ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
	if (ret) {
		dev_err(cpu_dev, "failed register driver: %d\n", ret);
		goto free_freq_table;
	}

	of_node_put(np);
	return 0;

free_freq_table:
	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_opp:
	if (free_opp)
		dev_pm_opp_of_remove_table(cpu_dev);
put_reg:
	if (!IS_ERR(arm_reg))
		regulator_put(arm_reg);
	if (!IS_ERR(pu_reg))
		regulator_put(pu_reg);
	if (!IS_ERR(soc_reg))
		regulator_put(soc_reg);
put_clk:
	if (!IS_ERR(arm_clk))
		clk_put(arm_clk);
	if (!IS_ERR(pll1_sys_clk))
		clk_put(pll1_sys_clk);
	if (!IS_ERR(pll1_sw_clk))
		clk_put(pll1_sw_clk);
	if (!IS_ERR(step_clk))
		clk_put(step_clk);
	if (!IS_ERR(pll2_pfd2_396m_clk))
		clk_put(pll2_pfd2_396m_clk);
	of_node_put(np);
	return ret;
}