^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Generic OPP OF helpers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009-2010 Texas Instruments Incorporated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Nishanth Menon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Romit Dasgupta
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Kevin Hilman
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/energy_model.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "opp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Returns opp descriptor node for a device node, caller must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * do of_node_put().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* "operating-points-v2" can be an array for power domain providers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return of_parse_phandle(np, "operating-points-v2", index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Returns opp descriptor node for a device, caller must do of_node_put() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return _opp_of_get_opp_desc_node(dev->of_node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct opp_table *_managed_opp(struct device *dev, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct opp_table *opp_table, *managed_table = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) np = _opp_of_get_opp_desc_node(dev->of_node, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) list_for_each_entry(opp_table, &opp_tables, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (opp_table->np == np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Multiple devices can point to the same OPP table and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * so will have same node-pointer, np.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * But the OPPs will be considered as shared only if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * OPP table contains a "opp-shared" property.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) _get_opp_table_kref(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) managed_table = opp_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return managed_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* The caller must call dev_pm_opp_put() after the OPP is used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct device_node *opp_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct dev_pm_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) mutex_lock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) list_for_each_entry(opp, &opp_table->opp_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (opp->np == opp_np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) dev_pm_opp_get(opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) mutex_unlock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) mutex_unlock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static struct device_node *of_parse_required_opp(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return of_parse_phandle(np, "required-opps", index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* The caller must call dev_pm_opp_put_opp_table() after the table is used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct opp_table *opp_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct device_node *opp_table_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) lockdep_assert_held(&opp_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) opp_table_np = of_get_parent(opp_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!opp_table_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* It is safe to put the node now as all we need now is its address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) of_node_put(opp_table_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) list_for_each_entry(opp_table, &opp_tables, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (opp_table_np == opp_table->np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) _get_opp_table_kref(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return opp_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* Free resources previously acquired by _opp_table_alloc_required_tables() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static void _opp_table_free_required_tables(struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct opp_table **required_opp_tables = opp_table->required_opp_tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (!required_opp_tables)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) for (i = 0; i < opp_table->required_opp_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (IS_ERR_OR_NULL(required_opp_tables[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) dev_pm_opp_put_opp_table(required_opp_tables[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) kfree(required_opp_tables);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) opp_table->required_opp_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) opp_table->required_opp_tables = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * Populate all devices and opp tables which are part of "required-opps" list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * Checking only the first OPP node should be enough.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct device_node *opp_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct opp_table **required_opp_tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct device_node *required_np, *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) int count, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /* Traversing the first OPP node is all we need */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) np = of_get_next_available_child(opp_np, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) dev_err(dev, "Empty OPP table\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) count = of_count_phandle_with_args(np, "required-opps", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) goto put_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (!required_opp_tables)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) goto put_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) opp_table->required_opp_tables = required_opp_tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) opp_table->required_opp_count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) required_np = of_parse_required_opp(np, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (!required_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) goto free_required_tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) required_opp_tables[i] = _find_table_of_opp_np(required_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) of_node_put(required_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (IS_ERR(required_opp_tables[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) goto free_required_tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * We only support genpd's OPPs in the "required-opps" for now,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * as we don't know how much about other cases. Error out if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * required OPP doesn't belong to a genpd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (!required_opp_tables[i]->is_genpd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) required_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto free_required_tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) goto put_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) free_required_tables:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) _opp_table_free_required_tables(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) put_np:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct device_node *np, *opp_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Only required for backward compatibility with v1 bindings, but isn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * harmful for other cases. And so we do it unconditionally.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) np = of_node_get(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (!of_property_read_u32(np, "clock-latency", &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) opp_table->clock_latency_ns_max = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) of_property_read_u32(np, "voltage-tolerance",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) &opp_table->voltage_tolerance_v1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (of_find_property(np, "#power-domain-cells", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) opp_table->is_genpd = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* Get OPP table node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) opp_np = _opp_of_get_opp_desc_node(np, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (!opp_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (of_property_read_bool(opp_np, "opp-shared"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) opp_table->np = opp_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) _opp_table_alloc_required_tables(opp_table, dev, opp_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) of_node_put(opp_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) void _of_clear_opp_table(struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) _opp_table_free_required_tables(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * Release all resources previously acquired with a call to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * _of_opp_alloc_required_opps().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) void _of_opp_free_required_opps(struct opp_table *opp_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct dev_pm_opp *opp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct dev_pm_opp **required_opps = opp->required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (!required_opps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) for (i = 0; i < opp_table->required_opp_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (!required_opps[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) /* Put the reference back */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) dev_pm_opp_put(required_opps[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) kfree(required_opps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) opp->required_opps = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Populate all required OPPs which are part of "required-opps" list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct dev_pm_opp *opp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct dev_pm_opp **required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct opp_table *required_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int i, ret, count = opp_table->required_opp_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) required_opps = kcalloc(count, sizeof(*required_opps), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (!required_opps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) opp->required_opps = required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) required_table = opp_table->required_opp_tables[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) np = of_parse_required_opp(opp->np, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (unlikely(!np)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) goto free_required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) required_opps[i] = _find_opp_of_np(required_table, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (!required_opps[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) __func__, opp->np, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) goto free_required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) free_required_opps:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) _of_opp_free_required_opps(opp_table, opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static int _bandwidth_supported(struct device *dev, struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct device_node *np, *opp_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (!opp_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) np = of_node_get(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) opp_np = _opp_of_get_opp_desc_node(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) opp_np = of_node_get(opp_table->np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /* Lets not fail in case we are parsing opp-v1 bindings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (!opp_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) /* Checking only first OPP is sufficient */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) np = of_get_next_available_child(opp_np, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) dev_err(dev, "OPP table empty\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) of_node_put(opp_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) prop = of_find_property(np, "opp-peak-kBps", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (!prop || !prop->length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) int dev_pm_opp_of_find_icc_paths(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int ret, i, count, num_paths;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) struct icc_path **paths;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) ret = _bandwidth_supported(dev, opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (ret <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) np = of_node_get(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) count = of_count_phandle_with_args(np, "interconnects",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) "#interconnect-cells");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /* two phandles when #interconnect-cells = <1> */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (count % 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) dev_err(dev, "%s: Invalid interconnects values\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) num_paths = count / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) paths = kcalloc(num_paths, sizeof(*paths), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (!paths)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) for (i = 0; i < num_paths; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) paths[i] = of_icc_get_by_index(dev, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (IS_ERR(paths[i])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) ret = PTR_ERR(paths[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (ret != -EPROBE_DEFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) dev_err(dev, "%s: Unable to get path%d: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) __func__, i, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (opp_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) opp_table->paths = paths;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) opp_table->path_count = num_paths;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) while (i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) icc_put(paths[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) kfree(paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) EXPORT_SYMBOL_GPL(dev_pm_opp_of_find_icc_paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) unsigned int levels = opp_table->supported_hw_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) int count, versions, ret, i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (!opp_table->supported_hw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * In the case that no supported_hw has been set by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * platform but there is an opp-supported-hw value set for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * an OPP then the OPP should not be enabled as there is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * no way to see if the hardware supports it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (of_find_property(np, "opp-supported-hw", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) count = of_property_count_u32_elems(np, "opp-supported-hw");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (count <= 0 || count % levels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) dev_err(dev, "%s: Invalid opp-supported-hw property (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) __func__, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) versions = count / levels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* All levels in at least one of the versions should match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) for (i = 0; i < versions; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) bool supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) for (j = 0; j < levels; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) ret = of_property_read_u32_index(np, "opp-supported-hw",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) i * levels + j, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) dev_warn(dev, "%s: failed to read opp-supported-hw property at index %d: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) __func__, i * levels + j, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* Check if the level is supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (!(val & opp_table->supported_hw[j])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) u32 *microvolt, *microamp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) int supplies = opp_table->regulator_count, vcount, icount, ret, i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct property *prop = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) char name[NAME_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* Search for "opp-microvolt-<name>" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (opp_table->prop_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) snprintf(name, sizeof(name), "opp-microvolt-%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) opp_table->prop_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) prop = of_find_property(opp->np, name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (!prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* Search for "opp-microvolt" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) sprintf(name, "opp-microvolt");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) prop = of_find_property(opp->np, name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) /* Missing property isn't a problem, but an invalid entry is */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (!prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (unlikely(supplies == -1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* Initialize regulator_count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) opp_table->regulator_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (!supplies)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (unlikely(supplies == -1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) /* Initialize regulator_count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) supplies = opp_table->regulator_count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) } else if (unlikely(!supplies)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) vcount = of_property_count_u32_elems(opp->np, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (vcount < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) dev_err(dev, "%s: Invalid %s property (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) __func__, name, vcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) return vcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) /* There can be one or three elements per supply */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (vcount != supplies && vcount != supplies * 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) __func__, name, vcount, supplies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (!microvolt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) goto free_microvolt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) /* Search for "opp-microamp-<name>" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) prop = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (opp_table->prop_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) snprintf(name, sizeof(name), "opp-microamp-%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) opp_table->prop_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) prop = of_find_property(opp->np, name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (!prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /* Search for "opp-microamp" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) sprintf(name, "opp-microamp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) prop = of_find_property(opp->np, name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) if (prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) icount = of_property_count_u32_elems(opp->np, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (icount < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) name, icount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) ret = icount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) goto free_microvolt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (icount != supplies) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) __func__, name, icount, supplies);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) goto free_microvolt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (!microamp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) goto free_microvolt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) ret = of_property_read_u32_array(opp->np, name, microamp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) icount);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) dev_err(dev, "%s: error parsing %s: %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) goto free_microamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) for (i = 0, j = 0; i < supplies; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) opp->supplies[i].u_volt = microvolt[j++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (vcount == supplies) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) opp->supplies[i].u_volt_min = microvolt[j++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) opp->supplies[i].u_volt_max = microvolt[j++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (microamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) opp->supplies[i].u_amp = microamp[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) free_microamp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) kfree(microamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) free_microvolt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) kfree(microvolt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * @dev: device pointer used to lookup OPP table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * Free OPPs created using static entries present in DT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) void dev_pm_opp_of_remove_table(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) dev_pm_opp_remove_table(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct device_node *np, bool peak)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) const char *name = peak ? "opp-peak-kBps" : "opp-avg-kBps";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) int i, count, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) u32 *bw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) prop = of_find_property(np, name, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) if (!prop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) count = prop->length / sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (table->path_count != count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) pr_err("%s: Mismatch between %s and paths (%d %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) __func__, name, count, table->path_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) bw = kmalloc_array(count, sizeof(*bw), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (!bw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) ret = of_property_read_u32_array(np, name, bw, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) pr_err("%s: Error parsing %s: %d\n", __func__, name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (peak)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) new_opp->bandwidth[i].peak = kBps_to_icc(bw[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) new_opp->bandwidth[i].avg = kBps_to_icc(bw[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) kfree(bw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) struct device_node *np, bool *rate_not_available)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) u64 rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) ret = of_property_read_u64(np, "opp-hz", &rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * Rate is defined as an unsigned long in clk API, and so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) * casting explicitly to its type. Must be fixed once rate is 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) * bit guaranteed in clk API.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) new_opp->rate = (unsigned long)rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) *rate_not_available = !!ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * Bandwidth consists of peak and average (optional) values:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * opp-peak-kBps = <path1_value path2_value>;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * opp-avg-kBps = <path1_value path2_value>;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) ret = _read_bw(new_opp, table, np, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) ret = _read_bw(new_opp, table, np, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* The properties were found but we failed to parse them */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (ret && ret != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (!of_property_read_u32(np, "opp-level", &new_opp->level))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) * @opp_table: OPP table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) * @dev: device for which we do this operation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) * @np: device node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * This function adds an opp definition to the opp table and returns status. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) * opp can be controlled using dev_pm_opp_enable/disable functions and may be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * removed by dev_pm_opp_remove.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * Valid OPP pointer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) * On success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) * NULL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) * Duplicate OPPs (both freq and volt are same) and opp->available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) * OR if the OPP is not supported by hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) * ERR_PTR(-EEXIST):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) * Freq are same and volt are different OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) * Duplicate OPPs (both freq and volt are same) and !opp->available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) * ERR_PTR(-ENOMEM):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) * Memory allocation failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) * ERR_PTR(-EINVAL):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) * Failed parsing the OPP node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) struct device *dev, struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) struct dev_pm_opp *new_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) bool rate_not_available = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) new_opp = _opp_allocate(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (!new_opp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) ret = _read_opp_key(new_opp, opp_table, np, &rate_not_available);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) if (ret < 0 && !opp_table->is_genpd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) dev_err(dev, "%s: opp key field not found\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) goto free_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) /* Check if the OPP supports hardware's hierarchy of versions or not */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) if (!_opp_is_supported(dev, opp_table, np)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) dev_dbg(dev, "OPP not supported by hardware: %lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) new_opp->rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) goto free_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) new_opp->turbo = of_property_read_bool(np, "turbo-mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) new_opp->np = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) new_opp->dynamic = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) new_opp->available = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) ret = _of_opp_alloc_required_opps(opp_table, new_opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) goto free_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (!of_property_read_u32(np, "clock-latency-ns", &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) new_opp->clock_latency_ns = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) ret = opp_parse_supplies(new_opp, dev, opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) goto free_required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (opp_table->is_genpd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) ret = _opp_add(dev, new_opp, opp_table, rate_not_available);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) /* Don't return error for duplicate OPPs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (ret == -EBUSY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) goto free_required_opps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) /* OPP to select on device suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) if (of_property_read_bool(np, "opp-suspend")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (opp_table->suspend_opp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) /* Pick the OPP with higher rate as suspend OPP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (new_opp->rate > opp_table->suspend_opp->rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) opp_table->suspend_opp->suspend = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) new_opp->suspend = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) opp_table->suspend_opp = new_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) new_opp->suspend = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) opp_table->suspend_opp = new_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) __func__, new_opp->turbo, new_opp->rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * Notify the changes in the availability of the operable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) * frequency/voltage list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) return new_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) free_required_opps:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) _of_opp_free_required_opps(opp_table, new_opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) free_opp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) _opp_free(new_opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) return ret ? ERR_PTR(ret) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) /* Initializes OPP tables based on new bindings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) int ret, count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) struct dev_pm_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) /* OPP table is already initialized for the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) mutex_lock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (opp_table->parsed_static_opps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) opp_table->parsed_static_opps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) mutex_unlock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) opp_table->parsed_static_opps = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) mutex_unlock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) /* We have opp-table node now, iterate over it and add OPPs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) for_each_available_child_of_node(opp_table->np, np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) opp = _opp_add_static_v2(opp_table, dev, np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (IS_ERR(opp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) ret = PTR_ERR(opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) goto remove_static_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) } else if (opp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /* There should be one or more OPPs defined */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (!count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) dev_err(dev, "%s: no supported OPPs", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) goto remove_static_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) list_for_each_entry(opp, &opp_table->opp_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) /* Any non-zero performance state would enable the feature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (opp->pstate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) opp_table->genpd_performance_state = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) remove_static_opp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) _opp_remove_all_static(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) /* Initializes OPP tables based on old-deprecated bindings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) const struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) const __be32 *val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) int nr, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) mutex_lock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (opp_table->parsed_static_opps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) opp_table->parsed_static_opps++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) mutex_unlock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) opp_table->parsed_static_opps = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) mutex_unlock(&opp_table->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) prop = of_find_property(dev->of_node, "operating-points", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) if (!prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) goto remove_static_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) if (!prop->value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) ret = -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) goto remove_static_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) * Each OPP is a set of tuples consisting of frequency and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) * voltage like <freq-kHz vol-uV>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) nr = prop->length / sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) if (nr % 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) dev_err(dev, "%s: Invalid OPP table\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) goto remove_static_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) val = prop->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) while (nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) unsigned long freq = be32_to_cpup(val++) * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) unsigned long volt = be32_to_cpup(val++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) ret = _opp_add_v1(opp_table, dev, freq, volt, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) __func__, freq, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) goto remove_static_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) nr -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) remove_static_opp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) _opp_remove_all_static(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) * dev_pm_opp_of_add_table() - Initialize opp table from device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) * @dev: device pointer used to lookup OPP table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) * Register the initial OPP table with the OPP library for given device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) * 0 On success OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * Duplicate OPPs (both freq and volt are same) and opp->available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) * -EEXIST Freq are same and volt are different OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * Duplicate OPPs (both freq and volt are same) and !opp->available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) * -ENOMEM Memory allocation failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * -ENODEV when 'operating-points' property is not found or is invalid data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) * in device node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) * -ENODATA when empty 'operating-points' property is found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * -EINVAL when invalid entries are found in opp-v2 table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) int dev_pm_opp_of_add_table(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) struct opp_table *opp_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) opp_table = dev_pm_opp_get_opp_table_indexed(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) if (IS_ERR(opp_table))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) return PTR_ERR(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) * OPPs have two version of bindings now. Also try the old (v1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) * bindings for backward compatibility with older dtbs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) if (opp_table->np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) ret = _of_add_opp_table_v2(dev, opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) ret = _of_add_opp_table_v1(dev, opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) dev_pm_opp_put_opp_table(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) * dev_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) * @dev: device pointer used to lookup OPP table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) * @index: Index number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) * Register the initial OPP table with the OPP library for given device only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) * using the "operating-points-v2" property.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) * 0 On success OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * Duplicate OPPs (both freq and volt are same) and opp->available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * -EEXIST Freq are same and volt are different OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * Duplicate OPPs (both freq and volt are same) and !opp->available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * -ENOMEM Memory allocation failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) * -ENODEV when 'operating-points' property is not found or is invalid data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * in device node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) * -ENODATA when empty 'operating-points' property is found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) * -EINVAL when invalid entries are found in opp-v2 table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) struct opp_table *opp_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) int ret, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) if (index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) * If only one phandle is present, then the same OPP table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) * applies for all index requests.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) count = of_count_phandle_with_args(dev->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) "operating-points-v2", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (count == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) opp_table = dev_pm_opp_get_opp_table_indexed(dev, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) if (IS_ERR(opp_table))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return PTR_ERR(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) ret = _of_add_opp_table_v2(dev, opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) dev_pm_opp_put_opp_table(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) /* CPU device specific helpers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) * dev_pm_opp_of_cpumask_remove_table() - Removes OPP table for @cpumask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) * @cpumask: cpumask for which OPP table needs to be removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) * This removes the OPP tables for CPUs present in the @cpumask.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) * This should be used only to remove static entries created from DT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) _dev_pm_opp_cpumask_remove_table(cpumask, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) * dev_pm_opp_of_cpumask_add_table() - Adds OPP table for @cpumask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) * @cpumask: cpumask for which OPP table needs to be added.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) * This adds the OPP tables for CPUs present in the @cpumask.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) struct device *cpu_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) int cpu, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) if (WARN_ON(cpumask_empty(cpumask)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) for_each_cpu(cpu, cpumask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) cpu_dev = get_cpu_device(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) if (!cpu_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) pr_err("%s: failed to get cpu%d device\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) goto remove_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) ret = dev_pm_opp_of_add_table(cpu_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) * OPP may get registered dynamically, don't print error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) * message here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) pr_debug("%s: couldn't find opp table for cpu:%d, %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) __func__, cpu, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) goto remove_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) remove_table:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) /* Free all other OPPs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) _dev_pm_opp_cpumask_remove_table(cpumask, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) * Works only for OPP v2 bindings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) * Returns -ENOENT if operating-points-v2 bindings aren't supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * dev_pm_opp_of_get_sharing_cpus() - Get cpumask of CPUs sharing OPPs with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * @cpu_dev using operating-points-v2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * bindings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * @cpu_dev: CPU device for which we do this operation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) * @cpumask: cpumask to update with information of sharing CPUs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) * Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) struct cpumask *cpumask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) struct device_node *np, *tmp_np, *cpu_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) int cpu, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) /* Get OPP descriptor node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) cpumask_set_cpu(cpu_dev->id, cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) /* OPPs are shared ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) if (!of_property_read_bool(np, "opp-shared"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) goto put_cpu_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) for_each_possible_cpu(cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) if (cpu == cpu_dev->id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) cpu_np = of_cpu_device_node_get(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) if (!cpu_np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) dev_err(cpu_dev, "%s: failed to get cpu%d node\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) __func__, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) goto put_cpu_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) /* Get OPP descriptor node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) tmp_np = _opp_of_get_opp_desc_node(cpu_np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) of_node_put(cpu_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) if (!tmp_np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) pr_err("%pOF: Couldn't find opp node\n", cpu_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) goto put_cpu_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) /* CPUs are sharing opp node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) if (np == tmp_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) cpumask_set_cpu(cpu, cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) of_node_put(tmp_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) put_cpu_node:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) * of_get_required_opp_performance_state() - Search for required OPP and return its performance state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) * @np: Node that contains the "required-opps" property.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) * @index: Index of the phandle to parse.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) * Returns the performance state of the OPP pointed out by the "required-opps"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) * property at @index in @np.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) * Return: Zero or positive performance state on success, otherwise negative
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) * value on errors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) int of_get_required_opp_performance_state(struct device_node *np, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) struct dev_pm_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) struct device_node *required_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) struct opp_table *opp_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) int pstate = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) required_np = of_parse_required_opp(np, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) if (!required_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) opp_table = _find_table_of_opp_np(required_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) if (IS_ERR(opp_table)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) pr_err("%s: Failed to find required OPP table %pOF: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) __func__, np, PTR_ERR(opp_table));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) goto put_required_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) opp = _find_opp_of_np(opp_table, required_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) if (opp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) pstate = opp->pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) dev_pm_opp_put(opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) dev_pm_opp_put_opp_table(opp_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) put_required_np:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) of_node_put(required_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) return pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) EXPORT_SYMBOL_GPL(of_get_required_opp_performance_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) * @opp: opp for which DT node has to be returned for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) * Return: DT node corresponding to the opp, else 0 on success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) * The caller needs to put the node with of_node_put() after using it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) if (IS_ERR_OR_NULL(opp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) pr_err("%s: Invalid parameters\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) return of_node_get(opp->np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) * Callback function provided to the Energy Model framework upon registration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) * This computes the power estimated by @dev at @kHz if it is the frequency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) * frequency and @mW to the associated power. The power is estimated as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) * P = C * V^2 * f with C being the device's capacitance and V and f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) * respectively the voltage and frequency of the OPP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) * Returns -EINVAL if the power calculation failed because of missing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) * parameters, 0 otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) struct dev_pm_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) unsigned long mV, Hz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) u32 cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) u64 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) np = of_node_get(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) Hz = *kHz * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) opp = dev_pm_opp_find_freq_ceil(dev, &Hz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) if (IS_ERR(opp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) mV = dev_pm_opp_get_voltage(opp) / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) dev_pm_opp_put(opp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if (!mV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) tmp = (u64)cap * mV * mV * (Hz / 1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) do_div(tmp, 1000000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) *mW = (unsigned long)tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) *kHz = Hz / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) * dev_pm_opp_of_register_em() - Attempt to register an Energy Model
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) * @dev : Device for which an Energy Model has to be registered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) * @cpus : CPUs for which an Energy Model has to be registered. For
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) * other type of devices it should be set to NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) * This checks whether the "dynamic-power-coefficient" devicetree property has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) * been specified, and tries to register an Energy Model with it if it has.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) * Having this property means the voltages are known for OPPs and the EM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) * might be calculated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) struct em_data_callback em_cb = EM_DATA_CB(_get_power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) int ret, nr_opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) u32 cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) if (IS_ERR_OR_NULL(dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) nr_opp = dev_pm_opp_get_opp_count(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) if (nr_opp <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) np = of_node_get(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) * Register an EM only if the 'dynamic-power-coefficient' property is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) * set in devicetree. It is assumed the voltage values are known if that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) * property is set since it is useless otherwise. If voltages are not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) * known, just let the EM registration fail with an error to alert the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) * user about the inconsistent configuration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if (ret || !cap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) dev_dbg(dev, "Couldn't find proper 'dynamic-power-coefficient' in DT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) dev_dbg(dev, "Couldn't register Energy Model %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em);