/* *Fetchnewparents * *new_dram_alt_parentandnew_dram_apb_parentareoptionalbut *new_dram_core_parentisnot.
*/
new_dram_core_parent = clk_get_parent_by_index(
priv->dram_core, freq->dram_core_parent_index - 1); if (!new_dram_core_parent) {
dev_err(dev, "failed to fetch new dram_core parent\n"); return -EINVAL;
} if (freq->dram_alt_parent_index) {
new_dram_alt_parent = clk_get_parent_by_index(
priv->dram_alt,
freq->dram_alt_parent_index - 1); if (!new_dram_alt_parent) {
dev_err(dev, "failed to fetch new dram_alt parent\n"); return -EINVAL;
}
} else
new_dram_alt_parent = NULL;
if (freq->dram_apb_parent_index) {
new_dram_apb_parent = clk_get_parent_by_index(
priv->dram_apb,
freq->dram_apb_parent_index - 1); if (!new_dram_apb_parent) {
dev_err(dev, "failed to fetch new dram_apb parent\n"); return -EINVAL;
}
} else
new_dram_apb_parent = NULL;
/* increase reference counts and ensure clks are ON before switch */
ret = clk_prepare_enable(new_dram_core_parent); if (ret) {
dev_err(dev, "failed to enable new dram_core parent: %d\n",
ret); goto out;
}
ret = clk_prepare_enable(new_dram_alt_parent); if (ret) {
dev_err(dev, "failed to enable new dram_alt parent: %d\n",
ret); goto out_disable_core_parent;
}
ret = clk_prepare_enable(new_dram_apb_parent); if (ret) {
dev_err(dev, "failed to enable new dram_apb parent: %d\n",
ret); goto out_disable_alt_parent;
}
imx8m_ddrc_smc_set_freq(freq->smcarg);
/* update parents in clk tree after switch. */
ret = clk_set_parent(priv->dram_core, new_dram_core_parent); if (ret)
dev_warn(dev, "failed to set dram_core parent: %d\n", ret); if (new_dram_alt_parent) {
ret = clk_set_parent(priv->dram_alt, new_dram_alt_parent); if (ret)
dev_warn(dev, "failed to set dram_alt parent: %d\n",
ret);
} if (new_dram_apb_parent) {
ret = clk_set_parent(priv->dram_apb, new_dram_apb_parent); if (ret)
dev_warn(dev, "failed to set dram_apb parent: %d\n",
ret);
}
new_opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(new_opp)) {
ret = PTR_ERR(new_opp);
dev_err(dev, "failed to get recommended opp: %d\n", ret); return ret;
}
dev_pm_opp_put(new_opp);
old_freq = clk_get_rate(priv->dram_core); if (*freq == old_freq) return0;
freq_info = imx8m_ddrc_find_freq(priv, *freq); if (!freq_info) return -EINVAL;
/* *Readbacktheclkratetoverifyswitchwascorrectandsothat *wecanreportitonallerrorpaths.
*/
ret = imx8m_ddrc_set_freq(dev, freq_info);
new_freq = clk_get_rate(priv->dram_core); if (ret)
dev_err(dev, "ddrc failed freq switch to %lu from %lu: error %d. now at %lu\n",
*freq, old_freq, ret, new_freq); elseif (*freq != new_freq)
dev_err(dev, "ddrc failed freq update to %lu from %lu, now at %lu\n",
*freq, old_freq, new_freq); else
dev_dbg(dev, "ddrc freq set to %lu (was %lu)\n",
*freq, old_freq);
/* An error here means DDR DVFS API not supported by firmware */
arm_smccc_smc(IMX_SIP_DDR_DVFS, IMX_SIP_DDR_DVFS_GET_FREQ_COUNT, 0, 0, 0, 0, 0, 0, &res);
priv->freq_count = res.a0; if (priv->freq_count <= 0 ||
priv->freq_count > IMX8M_DDRC_MAX_FREQ_COUNT) return -ENODEV;
for (index = 0; index < priv->freq_count; ++index) { struct imx8m_ddrc_freq *freq = &priv->freq_table[index];
arm_smccc_smc(IMX_SIP_DDR_DVFS, IMX_SIP_DDR_DVFS_GET_FREQ_INFO,
index, 0, 0, 0, 0, 0, &res); /* Result should be strictly positive */ if ((long)res.a0 <= 0) return -ENODEV;
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.