/* 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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }