Ejemplo n.º 1
0
/* Get legacy powerlevels from qcom,gpu-pwrlevels and populate the opp table */
static int adreno_get_legacy_pwrlevels(struct device *dev)
{
	struct device_node *child, *node;
	int ret;

	node = of_find_compatible_node(dev->of_node, NULL,
		"qcom,gpu-pwrlevels");
	if (!node) {
		dev_err(dev, "Could not find the GPU powerlevels\n");
		return -ENXIO;
	}

	for_each_child_of_node(node, child) {
		unsigned int val;

		ret = of_property_read_u32(child, "qcom,gpu-freq", &val);
		if (ret)
			continue;

		/*
		 * Skip the intentionally bogus clock value found at the bottom
		 * of most legacy frequency tables
		 */
		if (val != 27000000)
			dev_pm_opp_add(dev, val, 0);
	}
Ejemplo n.º 2
0
static int build_opp_table(struct device *dev, const struct cvb_table *table,
			   int speedo_value, unsigned long max_freq)
{
	const struct rail_alignment *align = &table->alignment;
	int i, ret, dfll_mv, min_mv, max_mv;

	min_mv = round_voltage(table->min_millivolts, align, UP);
	max_mv = round_voltage(table->max_millivolts, align, DOWN);

	for (i = 0; i < MAX_DVFS_FREQS; i++) {
		const struct cvb_table_freq_entry *entry = &table->entries[i];

		if (!entry->freq || (entry->freq > max_freq))
			break;

		dfll_mv = get_cvb_voltage(speedo_value, table->speedo_scale,
					  &entry->coefficients);
		dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale,
					    align);
		dfll_mv = clamp(dfll_mv, min_mv, max_mv);

		ret = dev_pm_opp_add(dev, entry->freq, dfll_mv * 1000);
		if (ret)
			return ret;
	}

	return 0;
}
Ejemplo n.º 3
0
static int init_juno_opps_from_scpi(struct device *dev)
{
	struct scpi_ops *scpi;
	struct scpi_dvfs_info *info;
	int i;

	scpi = get_scpi_ops();
	if (!scpi)
		return 0; /* Really need to defer until scpi available */

	/* Hard coded for Juno. 2 is GPU domain */
	info = scpi->dvfs_get_info(2);
	if (IS_ERR_OR_NULL(info))
		return PTR_ERR(info);

	for (i = 0; i < info->count; i++) {
		struct scpi_opp *e = &info->opps[i];
		dev_info(dev, "Mali OPP from SCPI: %u Hz @ %u mV\n",
				e->freq, e->m_volt);

		dev_pm_opp_add(dev, e->freq, e->m_volt * 1000);
	}

	return 0;
}
Ejemplo n.º 4
0
static int scpi_opp_table_ops(struct device *cpu_dev, bool remove)
{
	int idx, ret = 0;
	struct scpi_opp *opp;
	struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);

	if (IS_ERR(info))
		return PTR_ERR(info);

	if (!info->opps)
		return -EIO;

	for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
		if (remove)
			dev_pm_opp_remove(cpu_dev, opp->freq);
		else
			ret = dev_pm_opp_add(cpu_dev, opp->freq,
					     opp->m_volt * 1000);
		if (ret) {
			dev_warn(cpu_dev, "failed to add opp %uHz %umV\n",
				 opp->freq, opp->m_volt);
			while (idx-- > 0)
				dev_pm_opp_remove(cpu_dev, (--opp)->freq);
			return ret;
		}
	}
	return ret;
}
static int exynos5250_init_int_tables(struct busfreq_data_int *data)
{
	int i, err = 0;

	for (i = LV_0; i < _LV_END; i++) {
		err = dev_pm_opp_add(data->dev, exynos5_int_opp_table[i].clk,
				exynos5_int_opp_table[i].volt);
		if (err) {
			dev_err(data->dev, "Cannot add opp entries.\n");
			return err;
		}
	}

	return 0;
}
Ejemplo n.º 6
0
static int init_juno_opps_from_scpi(struct device *dev)
{
	struct scpi_opp *sopp;
	int i;

	/* Hard coded for Juno. 2 is GPU domain */
	sopp = scpi_dvfs_get_opps(2);
	if (IS_ERR_OR_NULL(sopp))
		return PTR_ERR(sopp);

	for (i = 0; i < sopp->count; i++) {
		struct scpi_opp_entry *e = &sopp->opp[i];
		dev_info(dev, "Mali OPP from SCPI: %u Hz @ %u mV\n",
				e->freq_hz, e->volt_mv);

		dev_pm_opp_add(dev, e->freq_hz, e->volt_mv * 1000);
	}

	return 0;
}
Ejemplo n.º 7
0
static int build_opp_table(const struct cvb_table *d,
                           int speedo_value,
                           unsigned long max_freq,
                           struct device *opp_dev)
{
    int i, ret, dfll_mv, min_mv, max_mv;
    const struct cvb_table_freq_entry *table = NULL;
    const struct rail_alignment *align = &d->alignment;

    min_mv = round_voltage(d->min_millivolts, align, UP);
    max_mv = round_voltage(d->max_millivolts, align, DOWN);

    for (i = 0; i < MAX_DVFS_FREQS; i++) {
        table = &d->cvb_table[i];
        if (!table->freq || (table->freq > max_freq))
            break;

        /*
         * FIXME after clk_round_rate/clk_determine_rate prototypes
         * have been updated
         */
        if (table->freq & (1<<31))
            continue;

        dfll_mv = get_cvb_voltage(
                      speedo_value, d->speedo_scale, &table->coefficients);
        dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align);
        dfll_mv = clamp(dfll_mv, min_mv, max_mv);

        ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000);
        if (ret)
            return ret;
    }

    return 0;
}
Ejemplo n.º 8
0
static int exynos4x12_init_tables(struct busfreq_data *data)
{
	unsigned int i;
	unsigned int tmp;
	int ret;

	/* Enable pause function for DREX2 DVFS */
	tmp = __raw_readl(EXYNOS4_DMC_PAUSE_CTRL);
	tmp |= EXYNOS4_DMC_PAUSE_ENABLE;
	__raw_writel(tmp, EXYNOS4_DMC_PAUSE_CTRL);

	tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);

	for (i = 0; i <  EX4x12_LV_NUM; i++) {
		tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
			EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
			EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
			EXYNOS4_CLKDIV_DMC0_DMC_MASK |
			EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
			EXYNOS4_CLKDIV_DMC0_DMCP_MASK);

		tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
					EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
			(exynos4x12_clkdiv_dmc0[i][1] <<
					EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
			(exynos4x12_clkdiv_dmc0[i][2] <<
					EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
			(exynos4x12_clkdiv_dmc0[i][3] <<
					EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
			(exynos4x12_clkdiv_dmc0[i][4] <<
					EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
			(exynos4x12_clkdiv_dmc0[i][5] <<
					EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT));

		data->dmc_divtable[i] = tmp;
	}

	tmp = 0; /* Max voltages for the reliability of the unknown */

	if (tmp > 8)
		tmp = 0;
	pr_debug("ASV Group of Exynos4x12 is %d\n", tmp);

	for (i = 0; i < EX4x12_LV_NUM; i++) {
		exynos4x12_mifclk_table[i].volt =
			exynos4x12_mif_step_50[tmp][i];
		exynos4x12_intclk_table[i].volt =
			exynos4x12_int_volt[tmp][i];
	}

	for (i = 0; i < EX4x12_LV_NUM; i++) {
		ret = dev_pm_opp_add(data->dev, exynos4x12_mifclk_table[i].clk,
			      exynos4x12_mifclk_table[i].volt);
		if (ret) {
			dev_err(data->dev, "Fail to add opp entries.\n");
			return ret;
		}
	}

	return 0;
}
Ejemplo n.º 9
0
static int exynos4210_init_tables(struct busfreq_data *data)
{
	u32 tmp;
	int mgrp;
	int i, err = 0;

	tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
	for (i = LV_0; i < EX4210_LV_NUM; i++) {
		tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
			EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
			EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
			EXYNOS4_CLKDIV_DMC0_DMC_MASK |
			EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
			EXYNOS4_CLKDIV_DMC0_DMCP_MASK |
			EXYNOS4_CLKDIV_DMC0_COPY2_MASK |
			EXYNOS4_CLKDIV_DMC0_CORETI_MASK);

		tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
					EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][1] <<
					EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][2] <<
					EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][3] <<
					EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][4] <<
					EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][5] <<
					EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][6] <<
					EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) |
			(exynos4210_clkdiv_dmc0[i][7] <<
					EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT));

		data->dmc_divtable[i] = tmp;
	}

	tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
	for (i = LV_0; i <  EX4210_LV_NUM; i++) {
		tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK |
			EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
			EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
			EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
			EXYNOS4_CLKDIV_TOP_ONENAND_MASK);

		tmp |= ((exynos4210_clkdiv_top[i][0] <<
					EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) |
			(exynos4210_clkdiv_top[i][1] <<
					EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
			(exynos4210_clkdiv_top[i][2] <<
					EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
			(exynos4210_clkdiv_top[i][3] <<
					EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
			(exynos4210_clkdiv_top[i][4] <<
					EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));

		data->top_divtable[i] = tmp;
	}

	/*
	 * TODO: init tmp based on busfreq_data
	 * (device-tree or platform-data)
	 */
	tmp = 0; /* Max voltages for the reliability of the unknown */

	pr_debug("ASV Group of Exynos4 is %d\n", tmp);
	/* Use merged grouping for voltage */
	switch (tmp) {
	case 0:
		mgrp = 0;
		break;
	case 1:
	case 2:
		mgrp = 1;
		break;
	case 3:
	case 4:
		mgrp = 2;
		break;
	case 5:
	case 6:
		mgrp = 3;
		break;
	case 7:
		mgrp = 4;
		break;
	default:
		pr_warn("Unknown ASV Group. Use max voltage.\n");
		mgrp = 0;
	}

	for (i = LV_0; i < EX4210_LV_NUM; i++)
		exynos4210_busclk_table[i].volt = exynos4210_asv_volt[mgrp][i];

	for (i = LV_0; i < EX4210_LV_NUM; i++) {
		err = dev_pm_opp_add(data->dev, exynos4210_busclk_table[i].clk,
			      exynos4210_busclk_table[i].volt);
		if (err) {
			dev_err(data->dev, "Cannot add opp entries.\n");
			return err;
		}
	}


	return 0;
}