opp_rate = *freq;
opp = devfreq_recommended_opp(dev, &opp_rate, 1); if (IS_ERR(opp)) {
dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate);
ret = PTR_ERR(opp); goto out_unlock;
}
voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
pre_voltage = regulator_get_voltage(drv->proc_reg); if (pre_voltage < 0) {
dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
ret = pre_voltage; goto out_unlock;
}
/* scale up: set voltage first then freq. */
target_voltage = max(inter_voltage, voltage); if (pre_voltage <= target_voltage) {
ret = mtk_ccifreq_set_voltage(drv, target_voltage); if (ret) {
dev_err(dev, "failed to scale up voltage\n"); goto out_restore_voltage;
}
}
/* switch the cci clock to intermediate clock source. */
ret = clk_set_parent(drv->cci_clk, drv->inter_clk); if (ret) {
dev_err(dev, "failed to re-parent cci clock\n"); goto out_restore_voltage;
}
/* set the original clock to target rate. */
ret = clk_set_rate(cci_pll, *freq); if (ret) {
dev_err(dev, "failed to set cci pll rate: %d\n", ret);
clk_set_parent(drv->cci_clk, cci_pll); goto out_restore_voltage;
}
/* switch the cci clock back to the original clock source. */
ret = clk_set_parent(drv->cci_clk, cci_pll); if (ret) {
dev_err(dev, "failed to re-parent cci clock\n");
mtk_ccifreq_set_voltage(drv, inter_voltage); goto out_unlock;
}
/* * If the new voltage is lower than the intermediate voltage or the * original voltage, scale down to the new voltage.
*/ if (voltage < inter_voltage || voltage < pre_voltage) {
ret = mtk_ccifreq_set_voltage(drv, voltage); if (ret) {
dev_err(dev, "failed to scale down voltage\n"); goto out_unlock;
}
}
if (event == OPP_EVENT_ADJUST_VOLTAGE) {
mutex_lock(&drv->reg_lock);
freq = dev_pm_opp_get_freq(opp);
/* current opp item is changed */ if (freq == drv->pre_freq) {
volt = dev_pm_opp_get_voltage(opp);
mtk_ccifreq_set_voltage(drv, volt);
}
mutex_unlock(&drv->reg_lock);
}
drv->cci_clk = devm_clk_get(dev, "cci"); if (IS_ERR(drv->cci_clk)) {
ret = PTR_ERR(drv->cci_clk); return dev_err_probe(dev, ret, "failed to get cci clk\n");
}
drv->inter_clk = devm_clk_get(dev, "intermediate"); if (IS_ERR(drv->inter_clk)) {
ret = PTR_ERR(drv->inter_clk); return dev_err_probe(dev, ret, "failed to get intermediate clk\n");
}
drv->proc_reg = devm_regulator_get_optional(dev, "proc"); if (IS_ERR(drv->proc_reg)) {
ret = PTR_ERR(drv->proc_reg); return dev_err_probe(dev, ret, "failed to get proc regulator\n");
}
ret = regulator_enable(drv->proc_reg); if (ret) {
dev_err(dev, "failed to enable proc regulator\n"); return ret;
}
drv->sram_reg = devm_regulator_get_optional(dev, "sram"); if (IS_ERR(drv->sram_reg)) {
ret = PTR_ERR(drv->sram_reg); if (ret == -EPROBE_DEFER) goto out_free_resources;
drv->sram_reg = NULL;
} else {
ret = regulator_enable(drv->sram_reg); if (ret) {
dev_err(dev, "failed to enable sram regulator\n"); goto out_free_resources;
}
}
/* * We assume min voltage is 0 and tracking target voltage using * min_volt_shift for each iteration. * The retry_max is 3 times of expected iteration count.
*/
drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
drv->soc_data->proc_max_volt),
drv->soc_data->min_volt_shift);
ret = clk_prepare_enable(drv->cci_clk); if (ret) goto out_free_resources;
ret = dev_pm_opp_of_add_table(dev); if (ret) {
dev_err(dev, "failed to add opp table: %d\n", ret); goto out_disable_cci_clk;
}
rate = clk_get_rate(drv->inter_clk);
opp = dev_pm_opp_find_freq_ceil(dev, &rate); if (IS_ERR(opp)) {
ret = PTR_ERR(opp);
dev_err(dev, "failed to get intermediate opp: %d\n", ret); goto out_remove_opp_table;
}
drv->inter_voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
rate = U32_MAX;
opp = dev_pm_opp_find_freq_floor(drv->dev, &rate); if (IS_ERR(opp)) {
dev_err(dev, "failed to get opp\n");
ret = PTR_ERR(opp); goto out_remove_opp_table;
}
opp_volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
ret = mtk_ccifreq_set_voltage(drv, opp_volt); if (ret) {
dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
opp_volt); goto out_remove_opp_table;
}
passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL); if (!passive_data) {
ret = -ENOMEM; goto out_remove_opp_table;
}
passive_data->parent_type = CPUFREQ_PARENT_DEV;
drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
DEVFREQ_GOV_PASSIVE,
passive_data); if (IS_ERR(drv->devfreq)) {
ret = -EPROBE_DEFER;
dev_err(dev, "failed to add devfreq device: %ld\n",
PTR_ERR(drv->devfreq)); goto out_remove_opp_table;
}
drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb); if (ret) {
dev_err(dev, "failed to register opp notifier: %d\n", ret); goto out_remove_opp_table;
} return 0;
out_free_resources: if (regulator_is_enabled(drv->proc_reg))
regulator_disable(drv->proc_reg); if (!IS_ERR_OR_NULL(drv->sram_reg) &&
regulator_is_enabled(drv->sram_reg))
regulator_disable(drv->sram_reg);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.