OPP updates for 5.20-rc1
- Make dev_pm_opp_set_regulators() accept NULL terminated list (Viresh Kumar). - Add dev_pm_opp_set_config() and friends and migrate other users/helpers to using them (Viresh Kumar). - Add support for multiple clocks for a device (Viresh Kumar and Krzysztof Kozlowski). - Configure resources before adding OPP table for Venus (Stanimir Varbanov). - Keep reference count up for opp->np and opp_table->np while they are still in use (Liang He). - Minor cleanups (Viresh Kumar and Yang Li). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmLoprIACgkQ0rkcPK6B Ehz2nBAApgYUDGkEjWcJufIxW1mH77uonzmWUV2jQBEcCvYnjdwhJ0RpQUT75Xnk hTYJ5v9UKwOVl+puPguUe7UzSmWcsI9AzJCj0Vr/LBiln+sawoI51lqOaNjCJkmZ VytQJB23DNsYJAG/0xM42+syu+IONJ4vCP/9m35sWlevfFihbfQsEK+iEKsseVgd sEwPvHyixLWyeaoAf+6apOBP2Lf+/3R8h6Iv0U8n8jOzUpQQ5r/RSDyZeARP7gze 64aXvsvr7D0Mc9GpevDJKGtPFbRNfq5I4Lg5MOZ8NQVjXOqlWJil3oYEnKQxIH0Y EEzcrSuWi3SEeHrQfj+GFs/D7z2ZHqmbg7yb4P7zSeqLvG+7Ey9aYOXOg5LykrYk 1rZQzenLMF91RnhdRLI22SJngokOYZjWBFp62mPqmEYtx2VsYQlxqGtJoCHYDRx3 QRp0ZYJBnHQMt7saiIRFdAAIz7/G5lkiUplVzqAWe7AEpUG3Y7kvIqfwi69s3I5S ERSf3qqx3dUGFXYoxwglEwaf8ZvKQnPOzOLmbyc9Hrj2MclfKf9vW+0/4J6iiDlu ITpsqEWUhtEjwCt3lbM6PWNRrCJHi6YkKw0sORxEWR639cqckmk6ZAuaRPeOob6a nZ/UvwU2LMRG1zZyrsB3bbUkijJ019RPySmjCXApLsoNT1qpUr0= =NHBQ -----END PGP SIGNATURE----- Merge tag 'opp-updates-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm Pull operating performance points (OPP) updates for 5.20-rc1 from Viresh Kumar: "- Make dev_pm_opp_set_regulators() accept NULL terminated list (Viresh Kumar). - Add dev_pm_opp_set_config() and friends and migrate other users/helpers to using them (Viresh Kumar). - Add support for multiple clocks for a device (Viresh Kumar and Krzysztof Kozlowski). - Configure resources before adding OPP table for Venus (Stanimir Varbanov). - Keep reference count up for opp->np and opp_table->np while they are still in use (Liang He). - Minor cleanups (Viresh Kumar and Yang Li)." * tag 'opp-updates-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: (43 commits) venus: pm_helpers: Fix warning in OPP during probe OPP: Don't drop opp->np reference while it is still in use OPP: Don't drop opp_table->np reference while it is still in use OPP: Remove dev{m}_pm_opp_of_add_table_noclk() PM / devfreq: tegra30: Register config_clks helper OPP: Allow config_clks helper for single clk case OPP: Provide a simple implementation to configure multiple clocks OPP: Assert clk_count == 1 for single clk helpers OPP: Add key specific assert() method to key finding helpers OPP: Compare bandwidths for all paths in _opp_compare_key() OPP: Allow multiple clocks for a device dt-bindings: opp: accept array of frequencies OPP: Make dev_pm_opp_set_opp() independent of frequency OPP: Reuse _opp_compare_key() in _opp_add_static_v2() OPP: Remove rate_not_available parameter to _opp_add() OPP: Use consistent names for OPP table instances OPP: Use generic key finding helpers for bandwidth key OPP: Use generic key finding helpers for level key OPP: Add generic key finding helpers and use them for freq APIs OPP: Remove dev_pm_opp_find_freq_ceil_by_volt() ...
This commit is contained in:
Коммит
f6e0b468da
|
@ -50,6 +50,16 @@ patternProperties:
|
|||
property to uniquely identify the OPP nodes exists. Devices like power
|
||||
domains must have another (implementation dependent) property.
|
||||
|
||||
Entries for multiple clocks shall be provided in the same field, as
|
||||
array of frequencies. The OPP binding doesn't provide any provisions
|
||||
to relate the values to their clocks or the order in which the clocks
|
||||
need to be configured and that is left for the implementation
|
||||
specific binding.
|
||||
minItems: 1
|
||||
maxItems: 16
|
||||
items:
|
||||
maxItems: 1
|
||||
|
||||
opp-microvolt:
|
||||
description: |
|
||||
Voltage for the OPP
|
||||
|
|
|
@ -29,9 +29,9 @@ struct private_data {
|
|||
|
||||
cpumask_var_t cpus;
|
||||
struct device *cpu_dev;
|
||||
struct opp_table *opp_table;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
bool have_static_opps;
|
||||
int opp_token;
|
||||
};
|
||||
|
||||
static LIST_HEAD(priv_list);
|
||||
|
@ -193,7 +193,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
|
|||
struct private_data *priv;
|
||||
struct device *cpu_dev;
|
||||
bool fallback = false;
|
||||
const char *reg_name;
|
||||
const char *reg_name[] = { NULL, NULL };
|
||||
int ret;
|
||||
|
||||
/* Check if this CPU is already covered by some other policy */
|
||||
|
@ -218,12 +218,11 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
|
|||
* OPP layer will be taking care of regulators now, but it needs to know
|
||||
* the name of the regulator first.
|
||||
*/
|
||||
reg_name = find_supply_name(cpu_dev);
|
||||
if (reg_name) {
|
||||
priv->opp_table = dev_pm_opp_set_regulators(cpu_dev, ®_name,
|
||||
1);
|
||||
if (IS_ERR(priv->opp_table)) {
|
||||
ret = PTR_ERR(priv->opp_table);
|
||||
reg_name[0] = find_supply_name(cpu_dev);
|
||||
if (reg_name[0]) {
|
||||
priv->opp_token = dev_pm_opp_set_regulators(cpu_dev, reg_name);
|
||||
if (priv->opp_token < 0) {
|
||||
ret = priv->opp_token;
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(cpu_dev, "failed to set regulators: %d\n",
|
||||
ret);
|
||||
|
@ -295,7 +294,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
|
|||
out:
|
||||
if (priv->have_static_opps)
|
||||
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
|
||||
dev_pm_opp_put_regulators(priv->opp_table);
|
||||
dev_pm_opp_put_regulators(priv->opp_token);
|
||||
free_cpumask:
|
||||
free_cpumask_var(priv->cpus);
|
||||
return ret;
|
||||
|
@ -309,7 +308,7 @@ static void dt_cpufreq_release(void)
|
|||
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
|
||||
if (priv->have_static_opps)
|
||||
dev_pm_opp_of_cpumask_remove_table(priv->cpus);
|
||||
dev_pm_opp_put_regulators(priv->opp_table);
|
||||
dev_pm_opp_put_regulators(priv->opp_token);
|
||||
free_cpumask_var(priv->cpus);
|
||||
list_del(&priv->node);
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
/* cpufreq-dt device registered by imx-cpufreq-dt */
|
||||
static struct platform_device *cpufreq_dt_pdev;
|
||||
static struct opp_table *cpufreq_opp_table;
|
||||
static struct device *cpu_dev;
|
||||
static int cpufreq_opp_token;
|
||||
|
||||
enum IMX7ULP_CPUFREQ_CLKS {
|
||||
ARM,
|
||||
|
@ -153,9 +153,9 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
|
||||
speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
|
||||
|
||||
cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
|
||||
if (IS_ERR(cpufreq_opp_table)) {
|
||||
ret = PTR_ERR(cpufreq_opp_table);
|
||||
cpufreq_opp_token = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
|
||||
if (cpufreq_opp_token < 0) {
|
||||
ret = cpufreq_opp_token;
|
||||
dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
|
|||
cpufreq_dt_pdev = platform_device_register_data(
|
||||
&pdev->dev, "cpufreq-dt", -1, NULL, 0);
|
||||
if (IS_ERR(cpufreq_dt_pdev)) {
|
||||
dev_pm_opp_put_supported_hw(cpufreq_opp_table);
|
||||
dev_pm_opp_put_supported_hw(cpufreq_opp_token);
|
||||
ret = PTR_ERR(cpufreq_dt_pdev);
|
||||
dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -176,7 +176,7 @@ static int imx_cpufreq_dt_remove(struct platform_device *pdev)
|
|||
{
|
||||
platform_device_unregister(cpufreq_dt_pdev);
|
||||
if (!of_machine_is_compatible("fsl,imx7ulp"))
|
||||
dev_pm_opp_put_supported_hw(cpufreq_opp_table);
|
||||
dev_pm_opp_put_supported_hw(cpufreq_opp_token);
|
||||
else
|
||||
clk_bulk_put(ARRAY_SIZE(imx7ulp_clks), imx7ulp_clks);
|
||||
|
||||
|
|
|
@ -55,9 +55,7 @@ struct qcom_cpufreq_match_data {
|
|||
};
|
||||
|
||||
struct qcom_cpufreq_drv {
|
||||
struct opp_table **names_opp_tables;
|
||||
struct opp_table **hw_opp_tables;
|
||||
struct opp_table **genpd_opp_tables;
|
||||
int *opp_tokens;
|
||||
u32 versions;
|
||||
const struct qcom_cpufreq_match_data *data;
|
||||
};
|
||||
|
@ -315,72 +313,43 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
|
|||
}
|
||||
of_node_put(np);
|
||||
|
||||
drv->names_opp_tables = kcalloc(num_possible_cpus(),
|
||||
sizeof(*drv->names_opp_tables),
|
||||
drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens),
|
||||
GFP_KERNEL);
|
||||
if (!drv->names_opp_tables) {
|
||||
if (!drv->opp_tokens) {
|
||||
ret = -ENOMEM;
|
||||
goto free_drv;
|
||||
}
|
||||
drv->hw_opp_tables = kcalloc(num_possible_cpus(),
|
||||
sizeof(*drv->hw_opp_tables),
|
||||
GFP_KERNEL);
|
||||
if (!drv->hw_opp_tables) {
|
||||
ret = -ENOMEM;
|
||||
goto free_opp_names;
|
||||
}
|
||||
|
||||
drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
|
||||
sizeof(*drv->genpd_opp_tables),
|
||||
GFP_KERNEL);
|
||||
if (!drv->genpd_opp_tables) {
|
||||
ret = -ENOMEM;
|
||||
goto free_opp;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct dev_pm_opp_config config = {
|
||||
.supported_hw = NULL,
|
||||
};
|
||||
|
||||
cpu_dev = get_cpu_device(cpu);
|
||||
if (NULL == cpu_dev) {
|
||||
ret = -ENODEV;
|
||||
goto free_genpd_opp;
|
||||
goto free_opp;
|
||||
}
|
||||
|
||||
if (drv->data->get_version) {
|
||||
config.supported_hw = &drv->versions;
|
||||
config.supported_hw_count = 1;
|
||||
|
||||
if (pvs_name) {
|
||||
drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
|
||||
cpu_dev,
|
||||
pvs_name);
|
||||
if (IS_ERR(drv->names_opp_tables[cpu])) {
|
||||
ret = PTR_ERR(drv->names_opp_tables[cpu]);
|
||||
dev_err(cpu_dev, "Failed to add OPP name %s\n",
|
||||
pvs_name);
|
||||
goto free_opp;
|
||||
}
|
||||
}
|
||||
|
||||
drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
|
||||
cpu_dev, &drv->versions, 1);
|
||||
if (IS_ERR(drv->hw_opp_tables[cpu])) {
|
||||
ret = PTR_ERR(drv->hw_opp_tables[cpu]);
|
||||
dev_err(cpu_dev,
|
||||
"Failed to set supported hardware\n");
|
||||
goto free_genpd_opp;
|
||||
}
|
||||
if (pvs_name)
|
||||
config.prop_name = pvs_name;
|
||||
}
|
||||
|
||||
if (drv->data->genpd_names) {
|
||||
drv->genpd_opp_tables[cpu] =
|
||||
dev_pm_opp_attach_genpd(cpu_dev,
|
||||
drv->data->genpd_names,
|
||||
NULL);
|
||||
if (IS_ERR(drv->genpd_opp_tables[cpu])) {
|
||||
ret = PTR_ERR(drv->genpd_opp_tables[cpu]);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(cpu_dev,
|
||||
"Could not attach to pm_domain: %d\n",
|
||||
ret);
|
||||
goto free_genpd_opp;
|
||||
config.genpd_names = drv->data->genpd_names;
|
||||
config.virt_devs = NULL;
|
||||
}
|
||||
|
||||
if (config.supported_hw || config.genpd_names) {
|
||||
drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config);
|
||||
if (drv->opp_tokens[cpu] < 0) {
|
||||
ret = drv->opp_tokens[cpu];
|
||||
dev_err(cpu_dev, "Failed to set OPP config\n");
|
||||
goto free_opp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,27 +364,10 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
|
|||
ret = PTR_ERR(cpufreq_dt_pdev);
|
||||
dev_err(cpu_dev, "Failed to register platform device\n");
|
||||
|
||||
free_genpd_opp:
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (IS_ERR(drv->genpd_opp_tables[cpu]))
|
||||
break;
|
||||
dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
|
||||
}
|
||||
kfree(drv->genpd_opp_tables);
|
||||
free_opp:
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (IS_ERR(drv->names_opp_tables[cpu]))
|
||||
break;
|
||||
dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
|
||||
}
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (IS_ERR(drv->hw_opp_tables[cpu]))
|
||||
break;
|
||||
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
|
||||
}
|
||||
kfree(drv->hw_opp_tables);
|
||||
free_opp_names:
|
||||
kfree(drv->names_opp_tables);
|
||||
for_each_possible_cpu(cpu)
|
||||
dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
|
||||
kfree(drv->opp_tokens);
|
||||
free_drv:
|
||||
kfree(drv);
|
||||
|
||||
|
@ -429,15 +381,10 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
|
|||
|
||||
platform_device_unregister(cpufreq_dt_pdev);
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
|
||||
dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
|
||||
dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
|
||||
}
|
||||
for_each_possible_cpu(cpu)
|
||||
dev_pm_opp_clear_config(drv->opp_tokens[cpu]);
|
||||
|
||||
kfree(drv->names_opp_tables);
|
||||
kfree(drv->hw_opp_tables);
|
||||
kfree(drv->genpd_opp_tables);
|
||||
kfree(drv->opp_tokens);
|
||||
kfree(drv);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -156,9 +156,13 @@ static int sti_cpufreq_set_opp_info(void)
|
|||
unsigned int hw_info_offset;
|
||||
unsigned int version[VERSION_ELEMENTS];
|
||||
int pcode, substrate, major, minor;
|
||||
int ret;
|
||||
int opp_token, ret;
|
||||
char name[MAX_PCODE_NAME_LEN];
|
||||
struct opp_table *opp_table;
|
||||
struct dev_pm_opp_config config = {
|
||||
.supported_hw = version,
|
||||
.supported_hw_count = ARRAY_SIZE(version),
|
||||
.prop_name = name,
|
||||
};
|
||||
|
||||
reg_fields = sti_cpufreq_match();
|
||||
if (!reg_fields) {
|
||||
|
@ -210,21 +214,14 @@ use_defaults:
|
|||
|
||||
snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
|
||||
|
||||
opp_table = dev_pm_opp_set_prop_name(dev, name);
|
||||
if (IS_ERR(opp_table)) {
|
||||
dev_err(dev, "Failed to set prop name\n");
|
||||
return PTR_ERR(opp_table);
|
||||
}
|
||||
|
||||
version[0] = BIT(major);
|
||||
version[1] = BIT(minor);
|
||||
version[2] = BIT(substrate);
|
||||
|
||||
opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
|
||||
if (IS_ERR(opp_table)) {
|
||||
dev_err(dev, "Failed to set supported hardware\n");
|
||||
ret = PTR_ERR(opp_table);
|
||||
goto err_put_prop_name;
|
||||
opp_token = dev_pm_opp_set_config(dev, &config);
|
||||
if (opp_token < 0) {
|
||||
dev_err(dev, "Failed to set OPP config\n");
|
||||
return opp_token;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
|
||||
|
@ -233,10 +230,6 @@ use_defaults:
|
|||
version[0], version[1], version[2]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_prop_name:
|
||||
dev_pm_opp_put_prop_name(opp_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sti_cpufreq_fetch_syscon_registers(void)
|
||||
|
|
|
@ -86,20 +86,20 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
|
|||
|
||||
static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct opp_table **opp_tables;
|
||||
int *opp_tokens;
|
||||
char name[MAX_NAME_LEN];
|
||||
unsigned int cpu;
|
||||
u32 speed = 0;
|
||||
int ret;
|
||||
|
||||
opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables),
|
||||
opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens),
|
||||
GFP_KERNEL);
|
||||
if (!opp_tables)
|
||||
if (!opp_tokens)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sun50i_cpufreq_get_efuse(&speed);
|
||||
if (ret) {
|
||||
kfree(opp_tables);
|
||||
kfree(opp_tokens);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -113,9 +113,9 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
|||
goto free_opp;
|
||||
}
|
||||
|
||||
opp_tables[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
|
||||
if (IS_ERR(opp_tables[cpu])) {
|
||||
ret = PTR_ERR(opp_tables[cpu]);
|
||||
opp_tokens[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
|
||||
if (opp_tokens[cpu] < 0) {
|
||||
ret = opp_tokens[cpu];
|
||||
pr_err("Failed to set prop name\n");
|
||||
goto free_opp;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
|||
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
|
||||
NULL, 0);
|
||||
if (!IS_ERR(cpufreq_dt_pdev)) {
|
||||
platform_set_drvdata(pdev, opp_tables);
|
||||
platform_set_drvdata(pdev, opp_tokens);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -132,27 +132,24 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
|
|||
pr_err("Failed to register platform device\n");
|
||||
|
||||
free_opp:
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (IS_ERR_OR_NULL(opp_tables[cpu]))
|
||||
break;
|
||||
dev_pm_opp_put_prop_name(opp_tables[cpu]);
|
||||
}
|
||||
kfree(opp_tables);
|
||||
for_each_possible_cpu(cpu)
|
||||
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
|
||||
kfree(opp_tokens);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct opp_table **opp_tables = platform_get_drvdata(pdev);
|
||||
int *opp_tokens = platform_get_drvdata(pdev);
|
||||
unsigned int cpu;
|
||||
|
||||
platform_device_unregister(cpufreq_dt_pdev);
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
dev_pm_opp_put_prop_name(opp_tables[cpu]);
|
||||
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
|
||||
|
||||
kfree(opp_tables);
|
||||
kfree(opp_tokens);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ static bool cpu0_node_has_opp_v2_prop(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void tegra20_cpufreq_put_supported_hw(void *opp_table)
|
||||
static void tegra20_cpufreq_put_supported_hw(void *opp_token)
|
||||
{
|
||||
dev_pm_opp_put_supported_hw(opp_table);
|
||||
dev_pm_opp_put_supported_hw((unsigned long) opp_token);
|
||||
}
|
||||
|
||||
static void tegra20_cpufreq_dt_unregister(void *cpufreq_dt)
|
||||
|
@ -45,7 +45,6 @@ static void tegra20_cpufreq_dt_unregister(void *cpufreq_dt)
|
|||
static int tegra20_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *cpufreq_dt;
|
||||
struct opp_table *opp_table;
|
||||
struct device *cpu_dev;
|
||||
u32 versions[2];
|
||||
int err;
|
||||
|
@ -71,16 +70,15 @@ static int tegra20_cpufreq_probe(struct platform_device *pdev)
|
|||
if (WARN_ON(!cpu_dev))
|
||||
return -ENODEV;
|
||||
|
||||
opp_table = dev_pm_opp_set_supported_hw(cpu_dev, versions, 2);
|
||||
err = PTR_ERR_OR_ZERO(opp_table);
|
||||
if (err) {
|
||||
err = dev_pm_opp_set_supported_hw(cpu_dev, versions, 2);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to set supported hw: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_add_action_or_reset(&pdev->dev,
|
||||
tegra20_cpufreq_put_supported_hw,
|
||||
opp_table);
|
||||
(void *)((unsigned long) err));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ struct ti_cpufreq_data {
|
|||
struct device_node *opp_node;
|
||||
struct regmap *syscon;
|
||||
const struct ti_cpufreq_soc_data *soc_data;
|
||||
struct opp_table *opp_table;
|
||||
};
|
||||
|
||||
static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
|
||||
|
@ -173,7 +172,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {
|
|||
* seems to always read as 0).
|
||||
*/
|
||||
|
||||
static const char * const omap3_reg_names[] = {"cpu0", "vbb"};
|
||||
static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL};
|
||||
|
||||
static struct ti_cpufreq_soc_data omap36xx_soc_data = {
|
||||
.reg_names = omap3_reg_names,
|
||||
|
@ -324,10 +323,13 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
|
|||
{
|
||||
u32 version[VERSION_COUNT];
|
||||
const struct of_device_id *match;
|
||||
struct opp_table *ti_opp_table;
|
||||
struct ti_cpufreq_data *opp_data;
|
||||
const char * const default_reg_names[] = {"vdd", "vbb"};
|
||||
const char * const default_reg_names[] = {"vdd", "vbb", NULL};
|
||||
int ret;
|
||||
struct dev_pm_opp_config config = {
|
||||
.supported_hw = version,
|
||||
.supported_hw_count = ARRAY_SIZE(version),
|
||||
};
|
||||
|
||||
match = dev_get_platdata(&pdev->dev);
|
||||
if (!match)
|
||||
|
@ -370,33 +372,21 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto fail_put_node;
|
||||
|
||||
ti_opp_table = dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
|
||||
version, VERSION_COUNT);
|
||||
if (IS_ERR(ti_opp_table)) {
|
||||
dev_err(opp_data->cpu_dev,
|
||||
"Failed to set supported hardware\n");
|
||||
ret = PTR_ERR(ti_opp_table);
|
||||
if (opp_data->soc_data->multi_regulator) {
|
||||
if (opp_data->soc_data->reg_names)
|
||||
config.regulator_names = opp_data->soc_data->reg_names;
|
||||
else
|
||||
config.regulator_names = default_reg_names;
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_set_config(opp_data->cpu_dev, &config);
|
||||
if (ret < 0) {
|
||||
dev_err(opp_data->cpu_dev, "Failed to set OPP config\n");
|
||||
goto fail_put_node;
|
||||
}
|
||||
|
||||
opp_data->opp_table = ti_opp_table;
|
||||
|
||||
if (opp_data->soc_data->multi_regulator) {
|
||||
const char * const *reg_names = default_reg_names;
|
||||
|
||||
if (opp_data->soc_data->reg_names)
|
||||
reg_names = opp_data->soc_data->reg_names;
|
||||
ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev,
|
||||
reg_names,
|
||||
ARRAY_SIZE(default_reg_names));
|
||||
if (IS_ERR(ti_opp_table)) {
|
||||
dev_pm_opp_put_supported_hw(opp_data->opp_table);
|
||||
ret = PTR_ERR(ti_opp_table);
|
||||
goto fail_put_node;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(opp_data->opp_node);
|
||||
|
||||
register_cpufreq_dt:
|
||||
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ struct exynos_bus {
|
|||
|
||||
unsigned long curr_freq;
|
||||
|
||||
struct opp_table *opp_table;
|
||||
int opp_token;
|
||||
struct clk *clk;
|
||||
unsigned int ratio;
|
||||
};
|
||||
|
@ -161,8 +161,7 @@ static void exynos_bus_exit(struct device *dev)
|
|||
|
||||
dev_pm_opp_of_remove_table(dev);
|
||||
clk_disable_unprepare(bus->clk);
|
||||
dev_pm_opp_put_regulators(bus->opp_table);
|
||||
bus->opp_table = NULL;
|
||||
dev_pm_opp_put_regulators(bus->opp_token);
|
||||
}
|
||||
|
||||
static void exynos_bus_passive_exit(struct device *dev)
|
||||
|
@ -179,18 +178,16 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
|
|||
struct exynos_bus *bus)
|
||||
{
|
||||
struct device *dev = bus->dev;
|
||||
struct opp_table *opp_table;
|
||||
const char *vdd = "vdd";
|
||||
const char *supplies[] = { "vdd", NULL };
|
||||
int i, ret, count, size;
|
||||
|
||||
opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1);
|
||||
if (IS_ERR(opp_table)) {
|
||||
ret = PTR_ERR(opp_table);
|
||||
ret = dev_pm_opp_set_regulators(dev, supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to set regulators %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bus->opp_table = opp_table;
|
||||
bus->opp_token = ret;
|
||||
|
||||
/*
|
||||
* Get the devfreq-event devices to get the current utilization of
|
||||
|
@ -236,8 +233,7 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
|
|||
return 0;
|
||||
|
||||
err_regulator:
|
||||
dev_pm_opp_put_regulators(bus->opp_table);
|
||||
bus->opp_table = NULL;
|
||||
dev_pm_opp_put_regulators(bus->opp_token);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -459,8 +455,7 @@ err:
|
|||
dev_pm_opp_of_remove_table(dev);
|
||||
clk_disable_unprepare(bus->clk);
|
||||
err_reg:
|
||||
dev_pm_opp_put_regulators(bus->opp_table);
|
||||
bus->opp_table = NULL;
|
||||
dev_pm_opp_put_regulators(bus->opp_token);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -821,6 +821,15 @@ static int devm_tegra_devfreq_init_hw(struct device *dev,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int tegra_devfreq_config_clks_nop(struct device *dev,
|
||||
struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down)
|
||||
{
|
||||
/* We want to skip clk configuration via dev_pm_opp_set_opp() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_devfreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
|
||||
|
@ -830,6 +839,13 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
|
|||
unsigned int i;
|
||||
long rate;
|
||||
int err;
|
||||
const char *clk_names[] = { "actmon", NULL };
|
||||
struct dev_pm_opp_config config = {
|
||||
.supported_hw = &hw_version,
|
||||
.supported_hw_count = 1,
|
||||
.clk_names = clk_names,
|
||||
.config_clks = tegra_devfreq_config_clks_nop,
|
||||
};
|
||||
|
||||
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
|
||||
if (!tegra)
|
||||
|
@ -874,13 +890,13 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = devm_pm_opp_set_supported_hw(&pdev->dev, &hw_version, 1);
|
||||
err = devm_pm_opp_set_config(&pdev->dev, &config);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err);
|
||||
dev_err(&pdev->dev, "Failed to set OPP config: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_pm_opp_of_add_table_noclk(&pdev->dev, 0);
|
||||
err = devm_pm_opp_of_add_table_indexed(&pdev->dev, 0);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
|
||||
return err;
|
||||
|
|
|
@ -111,6 +111,12 @@ int lima_devfreq_init(struct lima_device *ldev)
|
|||
struct dev_pm_opp *opp;
|
||||
unsigned long cur_freq;
|
||||
int ret;
|
||||
const char *regulator_names[] = { "mali", NULL };
|
||||
const char *clk_names[] = { "core", NULL };
|
||||
struct dev_pm_opp_config config = {
|
||||
.regulator_names = regulator_names,
|
||||
.clk_names = clk_names,
|
||||
};
|
||||
|
||||
if (!device_property_present(dev, "operating-points-v2"))
|
||||
/* Optional, continue without devfreq */
|
||||
|
@ -118,11 +124,7 @@ int lima_devfreq_init(struct lima_device *ldev)
|
|||
|
||||
spin_lock_init(&ldevfreq->lock);
|
||||
|
||||
ret = devm_pm_opp_set_clkname(dev, "core");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1);
|
||||
ret = devm_pm_opp_set_config(dev, &config);
|
||||
if (ret) {
|
||||
/* Continue if the optional regulator is missing */
|
||||
if (ret != -ENODEV)
|
||||
|
|
|
@ -101,8 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
|
||||
pfdev->comp->num_supplies);
|
||||
ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names);
|
||||
if (ret) {
|
||||
/* Continue if the optional regulator is missing */
|
||||
if (ret != -ENODEV) {
|
||||
|
|
|
@ -626,24 +626,29 @@ static int panfrost_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char * const default_supplies[] = { "mali" };
|
||||
/*
|
||||
* The OPP core wants the supply names to be NULL terminated, but we need the
|
||||
* correct num_supplies value for regulator core. Hence, we NULL terminate here
|
||||
* and then initialize num_supplies with ARRAY_SIZE - 1.
|
||||
*/
|
||||
static const char * const default_supplies[] = { "mali", NULL };
|
||||
static const struct panfrost_compatible default_data = {
|
||||
.num_supplies = ARRAY_SIZE(default_supplies),
|
||||
.num_supplies = ARRAY_SIZE(default_supplies) - 1,
|
||||
.supply_names = default_supplies,
|
||||
.num_pm_domains = 1, /* optional */
|
||||
.pm_domain_names = NULL,
|
||||
};
|
||||
|
||||
static const struct panfrost_compatible amlogic_data = {
|
||||
.num_supplies = ARRAY_SIZE(default_supplies),
|
||||
.num_supplies = ARRAY_SIZE(default_supplies) - 1,
|
||||
.supply_names = default_supplies,
|
||||
.vendor_quirk = panfrost_gpu_amlogic_quirk,
|
||||
};
|
||||
|
||||
static const char * const mediatek_mt8183_supplies[] = { "mali", "sram" };
|
||||
static const char * const mediatek_mt8183_supplies[] = { "mali", "sram", NULL };
|
||||
static const char * const mediatek_mt8183_pm_domains[] = { "core0", "core1", "core2" };
|
||||
static const struct panfrost_compatible mediatek_mt8183_data = {
|
||||
.num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies),
|
||||
.num_supplies = ARRAY_SIZE(mediatek_mt8183_supplies) - 1,
|
||||
.supply_names = mediatek_mt8183_supplies,
|
||||
.num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
|
||||
.pm_domain_names = mediatek_mt8183_pm_domains,
|
||||
|
|
|
@ -875,7 +875,7 @@ static int vcodec_domains_get(struct venus_core *core)
|
|||
}
|
||||
|
||||
skip_pmdomains:
|
||||
if (!core->has_opp_table)
|
||||
if (!core->res->opp_pmdomain)
|
||||
return 0;
|
||||
|
||||
/* Attach the power domain for setting performance state */
|
||||
|
@ -1007,6 +1007,10 @@ static int core_get_v4(struct venus_core *core)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vcodec_domains_get(core);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (core->res->opp_pmdomain) {
|
||||
ret = devm_pm_opp_of_add_table(dev);
|
||||
if (!ret) {
|
||||
|
@ -1017,10 +1021,6 @@ static int core_get_v4(struct venus_core *core)
|
|||
}
|
||||
}
|
||||
|
||||
ret = vcodec_domains_get(core);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1395,15 +1395,14 @@ err_msg:
|
|||
static int tegra_emc_opp_table_init(struct tegra_emc *emc)
|
||||
{
|
||||
u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
|
||||
struct opp_table *hw_opp_table;
|
||||
int err;
|
||||
int opp_token, err;
|
||||
|
||||
hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
|
||||
err = PTR_ERR_OR_ZERO(hw_opp_table);
|
||||
if (err) {
|
||||
err = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
|
||||
if (err < 0) {
|
||||
dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
opp_token = err;
|
||||
|
||||
err = dev_pm_opp_of_add_table(emc->dev);
|
||||
if (err) {
|
||||
|
@ -1430,7 +1429,7 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc)
|
|||
remove_table:
|
||||
dev_pm_opp_of_remove_table(emc->dev);
|
||||
put_hw_table:
|
||||
dev_pm_opp_put_supported_hw(hw_opp_table);
|
||||
dev_pm_opp_put_supported_hw(opp_token);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
1581
drivers/opp/core.c
1581
drivers/opp/core.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -41,7 +41,7 @@
|
|||
* the table if any of the mentioned functions have been invoked in the interim.
|
||||
*/
|
||||
int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||
struct cpufreq_frequency_table **table)
|
||||
struct cpufreq_frequency_table **opp_table)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
struct cpufreq_frequency_table *freq_table = NULL;
|
||||
|
@ -76,7 +76,7 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
|||
freq_table[i].driver_data = i;
|
||||
freq_table[i].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
*table = &freq_table[0];
|
||||
*opp_table = &freq_table[0];
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
|
@ -94,13 +94,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
|
|||
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
|
||||
*/
|
||||
void dev_pm_opp_free_cpufreq_table(struct device *dev,
|
||||
struct cpufreq_frequency_table **table)
|
||||
struct cpufreq_frequency_table **opp_table)
|
||||
{
|
||||
if (!table)
|
||||
if (!opp_table)
|
||||
return;
|
||||
|
||||
kfree(*table);
|
||||
*table = NULL;
|
||||
kfree(*opp_table);
|
||||
*opp_table = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
|
||||
#endif /* CONFIG_CPU_FREQ */
|
||||
|
|
|
@ -74,6 +74,24 @@ static void opp_debug_create_bw(struct dev_pm_opp *opp,
|
|||
}
|
||||
}
|
||||
|
||||
static void opp_debug_create_clks(struct dev_pm_opp *opp,
|
||||
struct opp_table *opp_table,
|
||||
struct dentry *pdentry)
|
||||
{
|
||||
char name[12];
|
||||
int i;
|
||||
|
||||
if (opp_table->clk_count == 1) {
|
||||
debugfs_create_ulong("rate_hz", S_IRUGO, pdentry, &opp->rates[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < opp_table->clk_count; i++) {
|
||||
snprintf(name, sizeof(name), "rate_hz_%d", i);
|
||||
debugfs_create_ulong(name, S_IRUGO, pdentry, &opp->rates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void opp_debug_create_supplies(struct dev_pm_opp *opp,
|
||||
struct opp_table *opp_table,
|
||||
struct dentry *pdentry)
|
||||
|
@ -117,10 +135,11 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
|
|||
* Get directory name for OPP.
|
||||
*
|
||||
* - Normally rate is unique to each OPP, use it to get unique opp-name.
|
||||
* - For some devices rate isn't available, use index instead.
|
||||
* - For some devices rate isn't available or there are multiple, use
|
||||
* index instead for them.
|
||||
*/
|
||||
if (likely(opp->rate))
|
||||
id = opp->rate;
|
||||
if (likely(opp_table->clk_count == 1 && opp->rates[0]))
|
||||
id = opp->rates[0];
|
||||
else
|
||||
id = _get_opp_count(opp_table);
|
||||
|
||||
|
@ -134,7 +153,6 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
|
|||
debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo);
|
||||
debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
|
||||
debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
|
||||
debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate);
|
||||
debugfs_create_u32("level", S_IRUGO, d, &opp->level);
|
||||
debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
|
||||
&opp->clock_latency_ns);
|
||||
|
@ -142,6 +160,7 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
|
|||
opp->of_name = of_node_full_name(opp->np);
|
||||
debugfs_create_str("of_name", S_IRUGO, d, (char **)&opp->of_name);
|
||||
|
||||
opp_debug_create_clks(opp, opp_table, d);
|
||||
opp_debug_create_supplies(opp, opp_table, d);
|
||||
opp_debug_create_bw(opp, opp_table, d);
|
||||
|
||||
|
|
150
drivers/opp/of.c
150
drivers/opp/of.c
|
@ -242,20 +242,20 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
|
|||
opp_table->np = opp_np;
|
||||
|
||||
_opp_table_alloc_required_tables(opp_table, dev, opp_np);
|
||||
of_node_put(opp_np);
|
||||
}
|
||||
|
||||
void _of_clear_opp_table(struct opp_table *opp_table)
|
||||
{
|
||||
_opp_table_free_required_tables(opp_table);
|
||||
of_node_put(opp_table->np);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release all resources previously acquired with a call to
|
||||
* _of_opp_alloc_required_opps().
|
||||
*/
|
||||
void _of_opp_free_required_opps(struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp)
|
||||
static void _of_opp_free_required_opps(struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp)
|
||||
{
|
||||
struct dev_pm_opp **required_opps = opp->required_opps;
|
||||
int i;
|
||||
|
@ -275,6 +275,12 @@ void _of_opp_free_required_opps(struct opp_table *opp_table,
|
|||
kfree(required_opps);
|
||||
}
|
||||
|
||||
void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp)
|
||||
{
|
||||
_of_opp_free_required_opps(opp_table, opp);
|
||||
of_node_put(opp->np);
|
||||
}
|
||||
|
||||
/* Populate all required OPPs which are part of "required-opps" list */
|
||||
static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp)
|
||||
|
@ -767,7 +773,51 @@ void dev_pm_opp_of_remove_table(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
|
||||
|
||||
static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
|
||||
static int _read_rate(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct property *prop;
|
||||
int i, count, ret;
|
||||
u64 *rates;
|
||||
|
||||
prop = of_find_property(np, "opp-hz", NULL);
|
||||
if (!prop)
|
||||
return -ENODEV;
|
||||
|
||||
count = prop->length / sizeof(u64);
|
||||
if (opp_table->clk_count != count) {
|
||||
pr_err("%s: Count mismatch between opp-hz and clk_count (%d %d)\n",
|
||||
__func__, count, opp_table->clk_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rates = kmalloc_array(count, sizeof(*rates), GFP_KERNEL);
|
||||
if (!rates)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u64_array(np, "opp-hz", rates, count);
|
||||
if (ret) {
|
||||
pr_err("%s: Error parsing opp-hz: %d\n", __func__, ret);
|
||||
} else {
|
||||
/*
|
||||
* Rate is defined as an unsigned long in clk API, and so
|
||||
* casting explicitly to its type. Must be fixed once rate is 64
|
||||
* bit guaranteed in clk API.
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
new_opp->rates[i] = (unsigned long)rates[i];
|
||||
|
||||
/* This will happen for frequencies > 4.29 GHz */
|
||||
WARN_ON(new_opp->rates[i] != rates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(rates);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
|
||||
struct device_node *np, bool peak)
|
||||
{
|
||||
const char *name = peak ? "opp-peak-kBps" : "opp-avg-kBps";
|
||||
|
@ -780,9 +830,9 @@ static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
|
|||
return -ENODEV;
|
||||
|
||||
count = prop->length / sizeof(u32);
|
||||
if (table->path_count != count) {
|
||||
if (opp_table->path_count != count) {
|
||||
pr_err("%s: Mismatch between %s and paths (%d %d)\n",
|
||||
__func__, name, count, table->path_count);
|
||||
__func__, name, count, opp_table->path_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -808,34 +858,27 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
|
||||
struct device_node *np, bool *rate_not_available)
|
||||
static int _read_opp_key(struct dev_pm_opp *new_opp,
|
||||
struct opp_table *opp_table, struct device_node *np)
|
||||
{
|
||||
bool found = false;
|
||||
u64 rate;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u64(np, "opp-hz", &rate);
|
||||
if (!ret) {
|
||||
/*
|
||||
* Rate is defined as an unsigned long in clk API, and so
|
||||
* casting explicitly to its type. Must be fixed once rate is 64
|
||||
* bit guaranteed in clk API.
|
||||
*/
|
||||
new_opp->rate = (unsigned long)rate;
|
||||
ret = _read_rate(new_opp, opp_table, np);
|
||||
if (!ret)
|
||||
found = true;
|
||||
}
|
||||
*rate_not_available = !!ret;
|
||||
else if (ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Bandwidth consists of peak and average (optional) values:
|
||||
* opp-peak-kBps = <path1_value path2_value>;
|
||||
* opp-avg-kBps = <path1_value path2_value>;
|
||||
*/
|
||||
ret = _read_bw(new_opp, table, np, true);
|
||||
ret = _read_bw(new_opp, opp_table, np, true);
|
||||
if (!ret) {
|
||||
found = true;
|
||||
ret = _read_bw(new_opp, table, np, false);
|
||||
ret = _read_bw(new_opp, opp_table, np, false);
|
||||
}
|
||||
|
||||
/* The properties were found but we failed to parse them */
|
||||
|
@ -881,13 +924,12 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
|
|||
struct dev_pm_opp *new_opp;
|
||||
u32 val;
|
||||
int ret;
|
||||
bool rate_not_available = false;
|
||||
|
||||
new_opp = _opp_allocate(opp_table);
|
||||
if (!new_opp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = _read_opp_key(new_opp, opp_table, np, &rate_not_available);
|
||||
ret = _read_opp_key(new_opp, opp_table, np);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: opp key field not found\n", __func__);
|
||||
goto free_opp;
|
||||
|
@ -895,14 +937,14 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
|
|||
|
||||
/* Check if the OPP supports hardware's hierarchy of versions or not */
|
||||
if (!_opp_is_supported(dev, opp_table, np)) {
|
||||
dev_dbg(dev, "OPP not supported by hardware: %lu\n",
|
||||
new_opp->rate);
|
||||
dev_dbg(dev, "OPP not supported by hardware: %s\n",
|
||||
of_node_full_name(np));
|
||||
goto free_opp;
|
||||
}
|
||||
|
||||
new_opp->turbo = of_property_read_bool(np, "turbo-mode");
|
||||
|
||||
new_opp->np = np;
|
||||
new_opp->np = of_node_get(np);
|
||||
new_opp->dynamic = false;
|
||||
new_opp->available = true;
|
||||
|
||||
|
@ -920,7 +962,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
|
|||
if (opp_table->is_genpd)
|
||||
new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
|
||||
|
||||
ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
|
||||
ret = _opp_add(dev, new_opp, opp_table);
|
||||
if (ret) {
|
||||
/* Don't return error for duplicate OPPs */
|
||||
if (ret == -EBUSY)
|
||||
|
@ -931,8 +973,8 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
|
|||
/* OPP to select on device suspend */
|
||||
if (of_property_read_bool(np, "opp-suspend")) {
|
||||
if (opp_table->suspend_opp) {
|
||||
/* Pick the OPP with higher rate as suspend OPP */
|
||||
if (new_opp->rate > opp_table->suspend_opp->rate) {
|
||||
/* Pick the OPP with higher rate/bw/level as suspend OPP */
|
||||
if (_opp_compare_key(opp_table, new_opp, opp_table->suspend_opp) == 1) {
|
||||
opp_table->suspend_opp->suspend = false;
|
||||
new_opp->suspend = true;
|
||||
opp_table->suspend_opp = new_opp;
|
||||
|
@ -947,7 +989,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
|
|||
opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
|
||||
|
||||
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu level:%u\n",
|
||||
__func__, new_opp->turbo, new_opp->rate,
|
||||
__func__, new_opp->turbo, new_opp->rates[0],
|
||||
new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
|
||||
new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns,
|
||||
new_opp->level);
|
||||
|
@ -1084,7 +1126,7 @@ remove_static_opp:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
|
||||
static int _of_add_table_indexed(struct device *dev, int index)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
int ret, count;
|
||||
|
@ -1100,7 +1142,7 @@ static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
|
|||
index = 0;
|
||||
}
|
||||
|
||||
opp_table = _add_opp_table_indexed(dev, index, getclk);
|
||||
opp_table = _add_opp_table_indexed(dev, index, true);
|
||||
if (IS_ERR(opp_table))
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
|
@ -1124,11 +1166,11 @@ static void devm_pm_opp_of_table_release(void *data)
|
|||
dev_pm_opp_of_remove_table(data);
|
||||
}
|
||||
|
||||
static int _devm_of_add_table_indexed(struct device *dev, int index, bool getclk)
|
||||
static int _devm_of_add_table_indexed(struct device *dev, int index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = _of_add_table_indexed(dev, index, getclk);
|
||||
ret = _of_add_table_indexed(dev, index);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1156,7 +1198,7 @@ static int _devm_of_add_table_indexed(struct device *dev, int index, bool getclk
|
|||
*/
|
||||
int devm_pm_opp_of_add_table(struct device *dev)
|
||||
{
|
||||
return _devm_of_add_table_indexed(dev, 0, true);
|
||||
return _devm_of_add_table_indexed(dev, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
|
||||
|
||||
|
@ -1179,7 +1221,7 @@ EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
|
|||
*/
|
||||
int dev_pm_opp_of_add_table(struct device *dev)
|
||||
{
|
||||
return _of_add_table_indexed(dev, 0, true);
|
||||
return _of_add_table_indexed(dev, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
|
||||
|
||||
|
@ -1195,7 +1237,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
|
|||
*/
|
||||
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
|
||||
{
|
||||
return _of_add_table_indexed(dev, index, true);
|
||||
return _of_add_table_indexed(dev, index);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
|
||||
|
||||
|
@ -1208,42 +1250,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
|
|||
*/
|
||||
int devm_pm_opp_of_add_table_indexed(struct device *dev, int index)
|
||||
{
|
||||
return _devm_of_add_table_indexed(dev, index, true);
|
||||
return _devm_of_add_table_indexed(dev, index);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_indexed);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
|
||||
* tree without getting clk for device.
|
||||
* @dev: device pointer used to lookup OPP table.
|
||||
* @index: Index number.
|
||||
*
|
||||
* Register the initial OPP table with the OPP library for given device only
|
||||
* using the "operating-points-v2" property. Do not try to get the clk for the
|
||||
* device.
|
||||
*
|
||||
* Return: Refer to dev_pm_opp_of_add_table() for return values.
|
||||
*/
|
||||
int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
|
||||
{
|
||||
return _of_add_table_indexed(dev, index, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_noclk);
|
||||
|
||||
/**
|
||||
* devm_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
|
||||
* tree without getting clk for device.
|
||||
* @dev: device pointer used to lookup OPP table.
|
||||
* @index: Index number.
|
||||
*
|
||||
* This is a resource-managed variant of dev_pm_opp_of_add_table_noclk().
|
||||
*/
|
||||
int devm_pm_opp_of_add_table_noclk(struct device *dev, int index)
|
||||
{
|
||||
return _devm_of_add_table_indexed(dev, index, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_noclk);
|
||||
|
||||
/* CPU device specific helpers */
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,27 @@ extern struct mutex opp_table_lock;
|
|||
|
||||
extern struct list_head opp_tables, lazy_opp_tables;
|
||||
|
||||
/* OPP Config flags */
|
||||
#define OPP_CONFIG_CLK BIT(0)
|
||||
#define OPP_CONFIG_REGULATOR BIT(1)
|
||||
#define OPP_CONFIG_REGULATOR_HELPER BIT(2)
|
||||
#define OPP_CONFIG_PROP_NAME BIT(3)
|
||||
#define OPP_CONFIG_SUPPORTED_HW BIT(4)
|
||||
#define OPP_CONFIG_GENPD BIT(5)
|
||||
|
||||
/**
|
||||
* struct opp_config_data - data for set config operations
|
||||
* @opp_table: OPP table
|
||||
* @flags: OPP config flags
|
||||
*
|
||||
* This structure stores the OPP config information for each OPP table
|
||||
* configuration by the callers.
|
||||
*/
|
||||
struct opp_config_data {
|
||||
struct opp_table *opp_table;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal data structure organization with the OPP layer library is as
|
||||
* follows:
|
||||
|
@ -58,7 +79,7 @@ extern struct list_head opp_tables, lazy_opp_tables;
|
|||
* @suspend: true if suspend OPP
|
||||
* @removed: flag indicating that OPP's reference is dropped by OPP core.
|
||||
* @pstate: Device's power domain's performance state.
|
||||
* @rate: Frequency in hertz
|
||||
* @rates: Frequencies in hertz
|
||||
* @level: Performance level
|
||||
* @supplies: Power supplies voltage/current values
|
||||
* @bandwidth: Interconnect bandwidth values
|
||||
|
@ -81,7 +102,7 @@ struct dev_pm_opp {
|
|||
bool suspend;
|
||||
bool removed;
|
||||
unsigned int pstate;
|
||||
unsigned long rate;
|
||||
unsigned long *rates;
|
||||
unsigned int level;
|
||||
|
||||
struct dev_pm_opp_supply *supplies;
|
||||
|
@ -138,7 +159,7 @@ enum opp_table_access {
|
|||
* @clock_latency_ns_max: Max clock latency in nanoseconds.
|
||||
* @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
|
||||
* @shared_opp: OPP is shared between multiple devices.
|
||||
* @current_rate: Currently configured frequency.
|
||||
* @rate_clk_single: Currently configured frequency for single clk.
|
||||
* @current_opp: Currently configured OPP for the table.
|
||||
* @suspend_opp: Pointer to OPP to be used during device suspend.
|
||||
* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
|
||||
|
@ -149,7 +170,11 @@ enum opp_table_access {
|
|||
* @supported_hw: Array of version number to support.
|
||||
* @supported_hw_count: Number of elements in supported_hw array.
|
||||
* @prop_name: A name to postfix to many DT properties, while parsing them.
|
||||
* @clk: Device's clock handle
|
||||
* @config_clks: Platform specific config_clks() callback.
|
||||
* @clks: Device's clock handles, for multiple clocks.
|
||||
* @clk: Device's clock handle, for single clock.
|
||||
* @clk_count: Number of clocks.
|
||||
* @config_regulators: Platform specific config_regulators() callback.
|
||||
* @regulators: Supply regulators
|
||||
* @regulator_count: Number of power supply regulators. Its value can be -1
|
||||
* (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt
|
||||
|
@ -159,9 +184,6 @@ enum opp_table_access {
|
|||
* @enabled: Set to true if the device's resources are enabled/configured.
|
||||
* @genpd_performance_state: Device's power domain support performance state.
|
||||
* @is_genpd: Marks if the OPP table belongs to a genpd.
|
||||
* @set_opp: Platform specific set_opp callback
|
||||
* @sod_supplies: Set opp data supplies
|
||||
* @set_opp_data: Data to be passed to set_opp callback
|
||||
* @dentry: debugfs dentry pointer of the real device directory (not links).
|
||||
* @dentry_name: Name of the real dentry.
|
||||
*
|
||||
|
@ -188,7 +210,7 @@ struct opp_table {
|
|||
|
||||
unsigned int parsed_static_opps;
|
||||
enum opp_table_access shared_opp;
|
||||
unsigned long current_rate;
|
||||
unsigned long rate_clk_single;
|
||||
struct dev_pm_opp *current_opp;
|
||||
struct dev_pm_opp *suspend_opp;
|
||||
|
||||
|
@ -200,7 +222,11 @@ struct opp_table {
|
|||
unsigned int *supported_hw;
|
||||
unsigned int supported_hw_count;
|
||||
const char *prop_name;
|
||||
config_clks_t config_clks;
|
||||
struct clk **clks;
|
||||
struct clk *clk;
|
||||
int clk_count;
|
||||
config_regulators_t config_regulators;
|
||||
struct regulator **regulators;
|
||||
int regulator_count;
|
||||
struct icc_path **paths;
|
||||
|
@ -209,10 +235,6 @@ struct opp_table {
|
|||
bool genpd_performance_state;
|
||||
bool is_genpd;
|
||||
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data);
|
||||
struct dev_pm_opp_supply *sod_supplies;
|
||||
struct dev_pm_set_opp_data *set_opp_data;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *dentry;
|
||||
char dentry_name[NAME_MAX];
|
||||
|
@ -228,8 +250,8 @@ struct opp_table *_find_opp_table(struct device *dev);
|
|||
struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
|
||||
struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
|
||||
void _opp_free(struct dev_pm_opp *opp);
|
||||
int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
|
||||
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
|
||||
int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
|
||||
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
|
||||
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
|
||||
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
|
||||
struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
|
||||
|
@ -245,14 +267,12 @@ static inline bool lazy_linking_pending(struct opp_table *opp_table)
|
|||
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
|
||||
void _of_clear_opp_table(struct opp_table *opp_table);
|
||||
struct opp_table *_managed_opp(struct device *dev, int index);
|
||||
void _of_opp_free_required_opps(struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp);
|
||||
void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp);
|
||||
#else
|
||||
static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}
|
||||
static inline void _of_clear_opp_table(struct opp_table *opp_table) {}
|
||||
static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }
|
||||
static inline void _of_opp_free_required_opps(struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp) {}
|
||||
static inline void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
|
|
@ -36,11 +36,15 @@ struct ti_opp_supply_optimum_voltage_table {
|
|||
* @vdd_table: Optimized voltage mapping table
|
||||
* @num_vdd_table: number of entries in vdd_table
|
||||
* @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply
|
||||
* @old_supplies: Placeholder for supplies information for old OPP.
|
||||
* @new_supplies: Placeholder for supplies information for new OPP.
|
||||
*/
|
||||
struct ti_opp_supply_data {
|
||||
struct ti_opp_supply_optimum_voltage_table *vdd_table;
|
||||
u32 num_vdd_table;
|
||||
u32 vdd_absolute_max_voltage_uv;
|
||||
struct dev_pm_opp_supply old_supplies[2];
|
||||
struct dev_pm_opp_supply new_supplies[2];
|
||||
};
|
||||
|
||||
static struct ti_opp_supply_data opp_data;
|
||||
|
@ -266,27 +270,32 @@ static int _opp_set_voltage(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_opp_supply_set_opp() - do the opp supply transition
|
||||
* @data: information on regulators and new and old opps provided by
|
||||
* opp core to use in transition
|
||||
*
|
||||
* Return: If successful, 0, else appropriate error value.
|
||||
*/
|
||||
static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
|
||||
/* Do the opp supply transition */
|
||||
static int ti_opp_config_regulators(struct device *dev,
|
||||
struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
|
||||
struct regulator **regulators, unsigned int count)
|
||||
{
|
||||
struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
|
||||
struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1];
|
||||
struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
|
||||
struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1];
|
||||
struct device *dev = data->dev;
|
||||
unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
|
||||
struct clk *clk = data->clk;
|
||||
struct regulator *vdd_reg = data->regulators[0];
|
||||
struct regulator *vbb_reg = data->regulators[1];
|
||||
struct dev_pm_opp_supply *old_supply_vdd = &opp_data.old_supplies[0];
|
||||
struct dev_pm_opp_supply *old_supply_vbb = &opp_data.old_supplies[1];
|
||||
struct dev_pm_opp_supply *new_supply_vdd = &opp_data.new_supplies[0];
|
||||
struct dev_pm_opp_supply *new_supply_vbb = &opp_data.new_supplies[1];
|
||||
struct regulator *vdd_reg = regulators[0];
|
||||
struct regulator *vbb_reg = regulators[1];
|
||||
unsigned long old_freq, freq;
|
||||
int vdd_uv;
|
||||
int ret;
|
||||
|
||||
/* We must have two regulators here */
|
||||
WARN_ON(count != 2);
|
||||
|
||||
/* Fetch supplies and freq information from OPP core */
|
||||
ret = dev_pm_opp_get_supplies(new_opp, opp_data.new_supplies);
|
||||
WARN_ON(ret);
|
||||
|
||||
old_freq = dev_pm_opp_get_freq(old_opp);
|
||||
freq = dev_pm_opp_get_freq(new_opp);
|
||||
WARN_ON(!old_freq || !freq);
|
||||
|
||||
vdd_uv = _get_optimal_vdd_voltage(dev, &opp_data,
|
||||
new_supply_vdd->u_volt);
|
||||
|
||||
|
@ -303,39 +312,24 @@ static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
|
|||
ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
|
||||
if (ret)
|
||||
goto restore_voltage;
|
||||
}
|
||||
|
||||
/* Change frequency */
|
||||
dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
|
||||
__func__, old_freq, freq);
|
||||
|
||||
ret = clk_set_rate(clk, freq);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
|
||||
ret);
|
||||
goto restore_voltage;
|
||||
}
|
||||
|
||||
/* Scaling down? Scale voltage after frequency */
|
||||
if (freq < old_freq) {
|
||||
} else {
|
||||
ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
|
||||
if (ret)
|
||||
goto restore_freq;
|
||||
goto restore_voltage;
|
||||
|
||||
ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
|
||||
"vdd");
|
||||
if (ret)
|
||||
goto restore_freq;
|
||||
goto restore_voltage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
restore_freq:
|
||||
ret = clk_set_rate(clk, old_freq);
|
||||
if (ret)
|
||||
dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
|
||||
__func__, old_freq);
|
||||
restore_voltage:
|
||||
/* Fetch old supplies information only if required */
|
||||
ret = dev_pm_opp_get_supplies(old_opp, opp_data.old_supplies);
|
||||
WARN_ON(ret);
|
||||
|
||||
/* This shouldn't harm even if the voltages weren't updated earlier */
|
||||
if (old_supply_vdd->u_volt) {
|
||||
ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb");
|
||||
|
@ -405,9 +399,8 @@ static int ti_opp_supply_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = PTR_ERR_OR_ZERO(dev_pm_opp_register_set_opp_helper(cpu_dev,
|
||||
ti_opp_supply_set_opp));
|
||||
if (ret)
|
||||
ret = dev_pm_opp_set_config_regulators(cpu_dev, ti_opp_config_regulators);
|
||||
if (ret < 0)
|
||||
_free_optimized_voltages(dev, &opp_data);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -107,29 +107,46 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev,
|
|||
{
|
||||
u32 hw_version;
|
||||
int err;
|
||||
/*
|
||||
* The clk's connection id to set is NULL and this is a NULL terminated
|
||||
* array, hence two NULL entries.
|
||||
*/
|
||||
const char *clk_names[] = { NULL, NULL };
|
||||
struct dev_pm_opp_config config = {
|
||||
/*
|
||||
* For some devices we don't have any OPP table in the DT, and
|
||||
* in order to use the same code path for all the devices, we
|
||||
* create a dummy OPP table for them via this. The dummy OPP
|
||||
* table is only capable of doing clk_set_rate() on invocation
|
||||
* of dev_pm_opp_set_rate() and doesn't provide any other
|
||||
* functionality.
|
||||
*/
|
||||
.clk_names = clk_names,
|
||||
};
|
||||
|
||||
err = devm_pm_opp_set_clkname(dev, NULL);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to set OPP clk: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Tegra114+ doesn't support OPP yet */
|
||||
if (!of_machine_is_compatible("nvidia,tegra20") &&
|
||||
!of_machine_is_compatible("nvidia,tegra30"))
|
||||
return -ENODEV;
|
||||
|
||||
if (of_machine_is_compatible("nvidia,tegra20"))
|
||||
if (of_machine_is_compatible("nvidia,tegra20")) {
|
||||
hw_version = BIT(tegra_sku_info.soc_process_id);
|
||||
else
|
||||
config.supported_hw = &hw_version;
|
||||
config.supported_hw_count = 1;
|
||||
} else if (of_machine_is_compatible("nvidia,tegra30")) {
|
||||
hw_version = BIT(tegra_sku_info.soc_speedo_id);
|
||||
config.supported_hw = &hw_version;
|
||||
config.supported_hw_count = 1;
|
||||
}
|
||||
|
||||
err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
|
||||
err = devm_pm_opp_set_config(dev, &config);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to set OPP supported HW: %d\n", err);
|
||||
dev_err(dev, "failed to set OPP config: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tegra114+ doesn't support OPP yet, return early for non tegra20/30
|
||||
* case.
|
||||
*/
|
||||
if (!config.supported_hw)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Older device-trees have an empty OPP table, we will get
|
||||
* -ENODEV from devm_pm_opp_of_add_table() in this case.
|
||||
|
|
|
@ -1384,7 +1384,7 @@ tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
|
|||
static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
const char *rname = "core";
|
||||
const char *rname[] = { "core", NULL};
|
||||
int err;
|
||||
|
||||
genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
|
||||
|
@ -1395,7 +1395,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
|
|||
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
|
||||
genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
|
||||
|
||||
err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
|
||||
err = devm_pm_opp_set_regulators(pmc->dev, rname);
|
||||
if (err)
|
||||
return dev_err_probe(pmc->dev, err,
|
||||
"failed to set core OPP regulator\n");
|
||||
|
|
|
@ -57,37 +57,39 @@ struct dev_pm_opp_icc_bw {
|
|||
u32 peak;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dev_pm_opp_info - OPP freq/voltage/current values
|
||||
* @rate: Target clk rate in hz
|
||||
* @supplies: Array of voltage/current values for all power supplies
|
||||
*
|
||||
* This structure stores the freq/voltage/current values for a single OPP.
|
||||
*/
|
||||
struct dev_pm_opp_info {
|
||||
unsigned long rate;
|
||||
struct dev_pm_opp_supply *supplies;
|
||||
};
|
||||
typedef int (*config_regulators_t)(struct device *dev,
|
||||
struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
|
||||
struct regulator **regulators, unsigned int count);
|
||||
|
||||
typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp, void *data, bool scaling_down);
|
||||
|
||||
/**
|
||||
* struct dev_pm_set_opp_data - Set OPP data
|
||||
* @old_opp: Old OPP info
|
||||
* @new_opp: New OPP info
|
||||
* @regulators: Array of regulator pointers
|
||||
* @regulator_count: Number of regulators
|
||||
* @clk: Pointer to clk
|
||||
* @dev: Pointer to the struct device
|
||||
* struct dev_pm_opp_config - Device OPP configuration values
|
||||
* @clk_names: Clk names, NULL terminated array.
|
||||
* @config_clks: Custom set clk helper.
|
||||
* @prop_name: Name to postfix to properties.
|
||||
* @config_regulators: Custom set regulator helper.
|
||||
* @supported_hw: Array of hierarchy of versions to match.
|
||||
* @supported_hw_count: Number of elements in the array.
|
||||
* @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
|
||||
* @genpd_names: Null terminated array of pointers containing names of genpd to
|
||||
* attach.
|
||||
* @virt_devs: Pointer to return the array of virtual devices.
|
||||
*
|
||||
* This structure contains all information required for setting an OPP.
|
||||
* This structure contains platform specific OPP configurations for the device.
|
||||
*/
|
||||
struct dev_pm_set_opp_data {
|
||||
struct dev_pm_opp_info old_opp;
|
||||
struct dev_pm_opp_info new_opp;
|
||||
|
||||
struct regulator **regulators;
|
||||
unsigned int regulator_count;
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
struct dev_pm_opp_config {
|
||||
/* NULL terminated */
|
||||
const char * const *clk_names;
|
||||
config_clks_t config_clks;
|
||||
const char *prop_name;
|
||||
config_regulators_t config_regulators;
|
||||
const unsigned int *supported_hw;
|
||||
unsigned int supported_hw_count;
|
||||
const char * const *regulator_names;
|
||||
const char * const *genpd_names;
|
||||
struct device ***virt_devs;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM_OPP)
|
||||
|
@ -97,6 +99,8 @@ void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
|
|||
|
||||
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
|
||||
|
||||
int dev_pm_opp_get_supplies(struct dev_pm_opp *opp, struct dev_pm_opp_supply *supplies);
|
||||
|
||||
unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp);
|
||||
|
||||
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
|
||||
|
@ -119,8 +123,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
|||
bool available);
|
||||
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
|
||||
unsigned long *freq);
|
||||
struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
|
||||
unsigned long u_volt);
|
||||
|
||||
struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
|
||||
unsigned int level);
|
||||
|
@ -154,23 +156,13 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq);
|
|||
int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb);
|
||||
int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb);
|
||||
|
||||
struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
|
||||
void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
|
||||
int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
|
||||
struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
|
||||
void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
|
||||
struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
|
||||
void dev_pm_opp_put_regulators(struct opp_table *opp_table);
|
||||
int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
|
||||
struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name);
|
||||
void dev_pm_opp_put_clkname(struct opp_table *opp_table);
|
||||
int devm_pm_opp_set_clkname(struct device *dev, const char *name);
|
||||
struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
|
||||
void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
|
||||
int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
|
||||
struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs);
|
||||
void dev_pm_opp_detach_genpd(struct opp_table *opp_table);
|
||||
int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs);
|
||||
int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
|
||||
int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config);
|
||||
void dev_pm_opp_clear_config(int token);
|
||||
int dev_pm_opp_config_clks_simple(struct device *dev,
|
||||
struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down);
|
||||
|
||||
struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp);
|
||||
int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
|
||||
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
|
||||
|
@ -198,6 +190,11 @@ static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int dev_pm_opp_get_supplies(struct dev_pm_opp *opp, struct dev_pm_opp_supply *supplies)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
|
||||
{
|
||||
return 0;
|
||||
|
@ -274,12 +271,6 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
|
|||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
|
||||
unsigned long u_volt)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
|
||||
unsigned long *freq)
|
||||
{
|
||||
|
@ -342,79 +333,21 @@ static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct noti
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
|
||||
const u32 *versions,
|
||||
unsigned int count)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_set_supported_hw(struct device *dev,
|
||||
const u32 *versions,
|
||||
unsigned int count)
|
||||
static inline int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data))
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data))
|
||||
static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
static inline void dev_pm_opp_clear_config(int token) {}
|
||||
|
||||
static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_set_regulators(struct device *dev,
|
||||
const char * const names[],
|
||||
unsigned int count)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_attach_genpd(struct device *dev,
|
||||
const char * const *names,
|
||||
struct device ***virt_devs)
|
||||
static inline int dev_pm_opp_config_clks_simple(struct device *dev,
|
||||
struct opp_table *opp_table, struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -469,8 +402,6 @@ static inline int dev_pm_opp_sync_regulators(struct device *dev)
|
|||
int dev_pm_opp_of_add_table(struct device *dev);
|
||||
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
|
||||
int devm_pm_opp_of_add_table_indexed(struct device *dev, int index);
|
||||
int dev_pm_opp_of_add_table_noclk(struct device *dev, int index);
|
||||
int devm_pm_opp_of_add_table_noclk(struct device *dev, int index);
|
||||
void dev_pm_opp_of_remove_table(struct device *dev);
|
||||
int devm_pm_opp_of_add_table(struct device *dev);
|
||||
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
|
||||
|
@ -501,16 +432,6 @@ static inline int devm_pm_opp_of_add_table_indexed(struct device *dev, int index
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int devm_pm_opp_of_add_table_noclk(struct device *dev, int index)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_of_remove_table(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
@ -565,4 +486,149 @@ static inline int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_ta
|
|||
}
|
||||
#endif
|
||||
|
||||
/* OPP Configuration helpers */
|
||||
|
||||
/* Regulators helpers */
|
||||
static inline int dev_pm_opp_set_regulators(struct device *dev,
|
||||
const char * const names[])
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.regulator_names = names,
|
||||
};
|
||||
|
||||
return dev_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_regulators(int token)
|
||||
{
|
||||
dev_pm_opp_clear_config(token);
|
||||
}
|
||||
|
||||
static inline int devm_pm_opp_set_regulators(struct device *dev,
|
||||
const char * const names[])
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.regulator_names = names,
|
||||
};
|
||||
|
||||
return devm_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
/* Supported-hw helpers */
|
||||
static inline int dev_pm_opp_set_supported_hw(struct device *dev,
|
||||
const u32 *versions,
|
||||
unsigned int count)
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.supported_hw = versions,
|
||||
.supported_hw_count = count,
|
||||
};
|
||||
|
||||
return dev_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_supported_hw(int token)
|
||||
{
|
||||
dev_pm_opp_clear_config(token);
|
||||
}
|
||||
|
||||
static inline int devm_pm_opp_set_supported_hw(struct device *dev,
|
||||
const u32 *versions,
|
||||
unsigned int count)
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.supported_hw = versions,
|
||||
.supported_hw_count = count,
|
||||
};
|
||||
|
||||
return devm_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
/* clkname helpers */
|
||||
static inline int dev_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
const char *names[] = { name, NULL };
|
||||
struct dev_pm_opp_config config = {
|
||||
.clk_names = names,
|
||||
};
|
||||
|
||||
return dev_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_clkname(int token)
|
||||
{
|
||||
dev_pm_opp_clear_config(token);
|
||||
}
|
||||
|
||||
static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
const char *names[] = { name, NULL };
|
||||
struct dev_pm_opp_config config = {
|
||||
.clk_names = names,
|
||||
};
|
||||
|
||||
return devm_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
/* config-regulators helpers */
|
||||
static inline int dev_pm_opp_set_config_regulators(struct device *dev,
|
||||
config_regulators_t helper)
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.config_regulators = helper,
|
||||
};
|
||||
|
||||
return dev_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_config_regulators(int token)
|
||||
{
|
||||
dev_pm_opp_clear_config(token);
|
||||
}
|
||||
|
||||
/* genpd helpers */
|
||||
static inline int dev_pm_opp_attach_genpd(struct device *dev,
|
||||
const char * const *names,
|
||||
struct device ***virt_devs)
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.genpd_names = names,
|
||||
.virt_devs = virt_devs,
|
||||
};
|
||||
|
||||
return dev_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_detach_genpd(int token)
|
||||
{
|
||||
dev_pm_opp_clear_config(token);
|
||||
}
|
||||
|
||||
static inline int devm_pm_opp_attach_genpd(struct device *dev,
|
||||
const char * const *names,
|
||||
struct device ***virt_devs)
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.genpd_names = names,
|
||||
.virt_devs = virt_devs,
|
||||
};
|
||||
|
||||
return devm_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
/* prop-name helpers */
|
||||
static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
|
||||
{
|
||||
struct dev_pm_opp_config config = {
|
||||
.prop_name = name,
|
||||
};
|
||||
|
||||
return dev_pm_opp_set_config(dev, &config);
|
||||
}
|
||||
|
||||
static inline void dev_pm_opp_put_prop_name(int token)
|
||||
{
|
||||
dev_pm_opp_clear_config(token);
|
||||
}
|
||||
|
||||
#endif /* __LINUX_OPP_H__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче