X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=drivers%2Fopp%2Fof.c;h=861cc75de329bc840541d28b40334b893e926f25;hb=2a4eb7358aba6beff7fa23f028c733310756e525;hp=7af0ddec936bb422c44e0cd2f92b89d6723579ee;hpb=6c084839877666d987ff8bc4e0facd3c02d99d61;p=linux.git diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 7af0ddec936b..861cc75de329 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -23,6 +23,24 @@ #include "opp.h" +/* + * Returns opp descriptor node for a device node, caller must + * do of_node_put(). + */ +static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np, + int index) +{ + /* "operating-points-v2" can be an array for power domain providers */ + return of_parse_phandle(np, "operating-points-v2", index); +} + +/* Returns opp descriptor node for a device, caller must do of_node_put() */ +struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) +{ + return _opp_of_get_opp_desc_node(dev->of_node, 0); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); + static struct opp_table *_managed_opp(const struct device_node *np) { struct opp_table *opp_table, *managed_table = NULL; @@ -52,24 +70,40 @@ static struct opp_table *_managed_opp(const struct device_node *np) return managed_table; } -void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) +void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, + int index) { - struct device_node *np; + struct device_node *np, *opp_np; + u32 val; /* * Only required for backward compatibility with v1 bindings, but isn't * harmful for other cases. And so we do it unconditionally. */ np = of_node_get(dev->of_node); - if (np) { - u32 val; - - if (!of_property_read_u32(np, "clock-latency", &val)) - opp_table->clock_latency_ns_max = val; - of_property_read_u32(np, "voltage-tolerance", - &opp_table->voltage_tolerance_v1); - of_node_put(np); - } + if (!np) + return; + + if (!of_property_read_u32(np, "clock-latency", &val)) + opp_table->clock_latency_ns_max = val; + of_property_read_u32(np, "voltage-tolerance", + &opp_table->voltage_tolerance_v1); + + /* Get OPP table node */ + opp_np = _opp_of_get_opp_desc_node(np, index); + of_node_put(np); + + if (!opp_np) + return; + + if (of_property_read_bool(opp_np, "opp-shared")) + opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; + else + opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE; + + opp_table->np = opp_np; + + of_node_put(opp_np); } static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table, @@ -245,26 +279,10 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, */ void dev_pm_opp_of_remove_table(struct device *dev) { - _dev_pm_opp_find_and_remove_table(dev, false); + _dev_pm_opp_find_and_remove_table(dev); } EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); -/* Returns opp descriptor node for a device node, caller must - * do of_node_put() */ -static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np, - int index) -{ - /* "operating-points-v2" can be an array for power domain providers */ - return of_parse_phandle(np, "operating-points-v2", index); -} - -/* Returns opp descriptor node for a device, caller must do of_node_put() */ -struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) -{ - return _opp_of_get_opp_desc_node(dev->of_node, 0); -} -EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); - /** * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) * @opp_table: OPP table @@ -378,7 +396,8 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, } /* Initializes OPP tables based on new bindings */ -static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) +static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np, + int index) { struct device_node *np; struct opp_table *opp_table; @@ -390,13 +409,21 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) /* OPPs are already managed */ if (!_add_opp_dev(dev, opp_table)) ret = -ENOMEM; + else if (!opp_table->parsed_static_opps) + goto initialize_static_opps; + else + kref_get(&opp_table->list_kref); + goto put_opp_table; } - opp_table = dev_pm_opp_get_opp_table(dev); + opp_table = dev_pm_opp_get_opp_table_indexed(dev, index); if (!opp_table) return -ENOMEM; +initialize_static_opps: + kref_init(&opp_table->list_kref); + /* We have opp-table node now, iterate over it and add OPPs */ for_each_available_child_of_node(opp_np, np) { count++; @@ -405,7 +432,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) if (ret) { dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); - _dev_pm_opp_remove_table(opp_table, dev, false); + _dev_pm_opp_remove_table(opp_table, dev); of_node_put(np); goto put_opp_table; } @@ -414,6 +441,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) /* There should be one of more OPP defined */ if (WARN_ON(!count)) { ret = -ENOENT; + _put_opp_list_kref(opp_table); goto put_opp_table; } @@ -425,17 +453,14 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) dev_err(dev, "Not all nodes have performance state set (%d: %d)\n", count, pstate_count); ret = -ENOENT; + _dev_pm_opp_remove_table(opp_table, dev); goto put_opp_table; } if (pstate_count) opp_table->genpd_performance_state = true; - opp_table->np = opp_np; - if (of_property_read_bool(opp_np, "opp-shared")) - opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; - else - opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE; + opp_table->parsed_static_opps = true; put_opp_table: dev_pm_opp_put_opp_table(opp_table); @@ -471,6 +496,8 @@ static int _of_add_opp_table_v1(struct device *dev) if (!opp_table) return -ENOMEM; + kref_init(&opp_table->list_kref); + val = prop->value; while (nr) { unsigned long freq = be32_to_cpup(val++) * 1000; @@ -480,7 +507,7 @@ static int _of_add_opp_table_v1(struct device *dev) if (ret) { dev_err(dev, "%s: Failed to add OPP %ld (%d)\n", __func__, freq, ret); - _dev_pm_opp_remove_table(opp_table, dev, false); + _dev_pm_opp_remove_table(opp_table, dev); break; } nr -= 2; @@ -525,7 +552,7 @@ int dev_pm_opp_of_add_table(struct device *dev) return _of_add_opp_table_v1(dev); } - ret = _of_add_opp_table_v2(dev, opp_np); + ret = _of_add_opp_table_v2(dev, opp_np, 0); of_node_put(opp_np); return ret; @@ -573,7 +600,7 @@ int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) return -ENODEV; } - ret = _of_add_opp_table_v2(dev, opp_np); + ret = _of_add_opp_table_v2(dev, opp_np, index); of_node_put(opp_np); return ret; @@ -591,7 +618,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed); */ void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask) { - _dev_pm_opp_cpumask_remove_table(cpumask, true); + _dev_pm_opp_cpumask_remove_table(cpumask, -1); } EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table); @@ -626,7 +653,7 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) __func__, cpu, ret); /* Free all other OPPs */ - dev_pm_opp_of_cpumask_remove_table(cpumask); + _dev_pm_opp_cpumask_remove_table(cpumask, cpu); break; } }