xref: /openbmc/linux/drivers/opp/of.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27813dd6fSViresh Kumar /*
37813dd6fSViresh Kumar  * Generic OPP OF helpers
47813dd6fSViresh Kumar  *
57813dd6fSViresh Kumar  * Copyright (C) 2009-2010 Texas Instruments Incorporated.
67813dd6fSViresh Kumar  *	Nishanth Menon
77813dd6fSViresh Kumar  *	Romit Dasgupta
87813dd6fSViresh Kumar  *	Kevin Hilman
97813dd6fSViresh Kumar  */
107813dd6fSViresh Kumar 
117813dd6fSViresh Kumar #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
127813dd6fSViresh Kumar 
137813dd6fSViresh Kumar #include <linux/cpu.h>
147813dd6fSViresh Kumar #include <linux/errno.h>
157813dd6fSViresh Kumar #include <linux/device.h>
16cd6f0f51SRob Herring #include <linux/of.h>
173ba98324SViresh Kumar #include <linux/pm_domain.h>
187813dd6fSViresh Kumar #include <linux/slab.h>
197813dd6fSViresh Kumar #include <linux/export.h>
20a4f342b9SQuentin Perret #include <linux/energy_model.h>
217813dd6fSViresh Kumar 
227813dd6fSViresh Kumar #include "opp.h"
237813dd6fSViresh Kumar 
2464aaeb70SViresh Kumar /* OPP tables with uninitialized required OPPs, protected by opp_table_lock */
25167eb2bdSViresh Kumar static LIST_HEAD(lazy_opp_tables);
26167eb2bdSViresh Kumar 
27f06ed90eSViresh Kumar /*
28f06ed90eSViresh Kumar  * Returns opp descriptor node for a device node, caller must
29f06ed90eSViresh Kumar  * do of_node_put().
30f06ed90eSViresh Kumar  */
_opp_of_get_opp_desc_node(struct device_node * np,int index)31f06ed90eSViresh Kumar static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np,
32f06ed90eSViresh Kumar 						     int index)
33f06ed90eSViresh Kumar {
34f06ed90eSViresh Kumar 	/* "operating-points-v2" can be an array for power domain providers */
35f06ed90eSViresh Kumar 	return of_parse_phandle(np, "operating-points-v2", index);
36f06ed90eSViresh Kumar }
37f06ed90eSViresh Kumar 
38f06ed90eSViresh Kumar /* Returns opp descriptor node for a device, caller must do of_node_put() */
dev_pm_opp_of_get_opp_desc_node(struct device * dev)39f06ed90eSViresh Kumar struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
40f06ed90eSViresh Kumar {
41f06ed90eSViresh Kumar 	return _opp_of_get_opp_desc_node(dev->of_node, 0);
42f06ed90eSViresh Kumar }
43f06ed90eSViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
44f06ed90eSViresh Kumar 
_managed_opp(struct device * dev,int index)45283d55e6SViresh Kumar struct opp_table *_managed_opp(struct device *dev, int index)
467813dd6fSViresh Kumar {
477813dd6fSViresh Kumar 	struct opp_table *opp_table, *managed_table = NULL;
48283d55e6SViresh Kumar 	struct device_node *np;
497813dd6fSViresh Kumar 
50283d55e6SViresh Kumar 	np = _opp_of_get_opp_desc_node(dev->of_node, index);
51283d55e6SViresh Kumar 	if (!np)
52283d55e6SViresh Kumar 		return NULL;
537813dd6fSViresh Kumar 
547813dd6fSViresh Kumar 	list_for_each_entry(opp_table, &opp_tables, node) {
557813dd6fSViresh Kumar 		if (opp_table->np == np) {
567813dd6fSViresh Kumar 			/*
577813dd6fSViresh Kumar 			 * Multiple devices can point to the same OPP table and
587813dd6fSViresh Kumar 			 * so will have same node-pointer, np.
597813dd6fSViresh Kumar 			 *
607813dd6fSViresh Kumar 			 * But the OPPs will be considered as shared only if the
617813dd6fSViresh Kumar 			 * OPP table contains a "opp-shared" property.
627813dd6fSViresh Kumar 			 */
637813dd6fSViresh Kumar 			if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
647813dd6fSViresh Kumar 				_get_opp_table_kref(opp_table);
657813dd6fSViresh Kumar 				managed_table = opp_table;
667813dd6fSViresh Kumar 			}
677813dd6fSViresh Kumar 
687813dd6fSViresh Kumar 			break;
697813dd6fSViresh Kumar 		}
707813dd6fSViresh Kumar 	}
717813dd6fSViresh Kumar 
72283d55e6SViresh Kumar 	of_node_put(np);
737813dd6fSViresh Kumar 
747813dd6fSViresh Kumar 	return managed_table;
757813dd6fSViresh Kumar }
767813dd6fSViresh Kumar 
775d6d106fSViresh Kumar /* The caller must call dev_pm_opp_put() after the OPP is used */
_find_opp_of_np(struct opp_table * opp_table,struct device_node * opp_np)785d6d106fSViresh Kumar static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table,
795d6d106fSViresh Kumar 					  struct device_node *opp_np)
805d6d106fSViresh Kumar {
815d6d106fSViresh Kumar 	struct dev_pm_opp *opp;
825d6d106fSViresh Kumar 
835d6d106fSViresh Kumar 	mutex_lock(&opp_table->lock);
845d6d106fSViresh Kumar 
855d6d106fSViresh Kumar 	list_for_each_entry(opp, &opp_table->opp_list, node) {
865d6d106fSViresh Kumar 		if (opp->np == opp_np) {
875d6d106fSViresh Kumar 			dev_pm_opp_get(opp);
885d6d106fSViresh Kumar 			mutex_unlock(&opp_table->lock);
895d6d106fSViresh Kumar 			return opp;
905d6d106fSViresh Kumar 		}
915d6d106fSViresh Kumar 	}
925d6d106fSViresh Kumar 
935d6d106fSViresh Kumar 	mutex_unlock(&opp_table->lock);
945d6d106fSViresh Kumar 
955d6d106fSViresh Kumar 	return NULL;
965d6d106fSViresh Kumar }
975d6d106fSViresh Kumar 
of_parse_required_opp(struct device_node * np,int index)985d6d106fSViresh Kumar static struct device_node *of_parse_required_opp(struct device_node *np,
995d6d106fSViresh Kumar 						 int index)
1005d6d106fSViresh Kumar {
101020d86fcSRajendra Nayak 	return of_parse_phandle(np, "required-opps", index);
1025d6d106fSViresh Kumar }
1035d6d106fSViresh Kumar 
1045d6d106fSViresh Kumar /* The caller must call dev_pm_opp_put_opp_table() after the table is used */
_find_table_of_opp_np(struct device_node * opp_np)1055d6d106fSViresh Kumar static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)
1065d6d106fSViresh Kumar {
1075d6d106fSViresh Kumar 	struct opp_table *opp_table;
108699e21e4SViresh Kumar 	struct device_node *opp_table_np;
1095d6d106fSViresh Kumar 
110699e21e4SViresh Kumar 	opp_table_np = of_get_parent(opp_np);
111699e21e4SViresh Kumar 	if (!opp_table_np)
112699e21e4SViresh Kumar 		goto err;
113699e21e4SViresh Kumar 
114699e21e4SViresh Kumar 	/* It is safe to put the node now as all we need now is its address */
115699e21e4SViresh Kumar 	of_node_put(opp_table_np);
116699e21e4SViresh Kumar 
11727c09484SViresh Kumar 	mutex_lock(&opp_table_lock);
1185d6d106fSViresh Kumar 	list_for_each_entry(opp_table, &opp_tables, node) {
119699e21e4SViresh Kumar 		if (opp_table_np == opp_table->np) {
1205d6d106fSViresh Kumar 			_get_opp_table_kref(opp_table);
12127c09484SViresh Kumar 			mutex_unlock(&opp_table_lock);
1225d6d106fSViresh Kumar 			return opp_table;
1235d6d106fSViresh Kumar 		}
1245d6d106fSViresh Kumar 	}
12527c09484SViresh Kumar 	mutex_unlock(&opp_table_lock);
1265d6d106fSViresh Kumar 
127699e21e4SViresh Kumar err:
1285d6d106fSViresh Kumar 	return ERR_PTR(-ENODEV);
1295d6d106fSViresh Kumar }
1305d6d106fSViresh Kumar 
1315d6d106fSViresh Kumar /* Free resources previously acquired by _opp_table_alloc_required_tables() */
_opp_table_free_required_tables(struct opp_table * opp_table)1325d6d106fSViresh Kumar static void _opp_table_free_required_tables(struct opp_table *opp_table)
1335d6d106fSViresh Kumar {
1345d6d106fSViresh Kumar 	struct opp_table **required_opp_tables = opp_table->required_opp_tables;
1355d6d106fSViresh Kumar 	int i;
1365d6d106fSViresh Kumar 
1375d6d106fSViresh Kumar 	if (!required_opp_tables)
1385d6d106fSViresh Kumar 		return;
1395d6d106fSViresh Kumar 
1405d6d106fSViresh Kumar 	for (i = 0; i < opp_table->required_opp_count; i++) {
1415d6d106fSViresh Kumar 		if (IS_ERR_OR_NULL(required_opp_tables[i]))
1427eba0c76SViresh Kumar 			continue;
1435d6d106fSViresh Kumar 
1445d6d106fSViresh Kumar 		dev_pm_opp_put_opp_table(required_opp_tables[i]);
1455d6d106fSViresh Kumar 	}
1465d6d106fSViresh Kumar 
1475d6d106fSViresh Kumar 	kfree(required_opp_tables);
1485d6d106fSViresh Kumar 
1495d6d106fSViresh Kumar 	opp_table->required_opp_count = 0;
1505d6d106fSViresh Kumar 	opp_table->required_opp_tables = NULL;
15164aaeb70SViresh Kumar 
15264aaeb70SViresh Kumar 	mutex_lock(&opp_table_lock);
1537eba0c76SViresh Kumar 	list_del(&opp_table->lazy);
15464aaeb70SViresh Kumar 	mutex_unlock(&opp_table_lock);
1555d6d106fSViresh Kumar }
1565d6d106fSViresh Kumar 
1575d6d106fSViresh Kumar /*
1585d6d106fSViresh Kumar  * Populate all devices and opp tables which are part of "required-opps" list.
1595d6d106fSViresh Kumar  * Checking only the first OPP node should be enough.
1605d6d106fSViresh Kumar  */
_opp_table_alloc_required_tables(struct opp_table * opp_table,struct device * dev,struct device_node * opp_np)1615d6d106fSViresh Kumar static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
1625d6d106fSViresh Kumar 					     struct device *dev,
1635d6d106fSViresh Kumar 					     struct device_node *opp_np)
1645d6d106fSViresh Kumar {
1655d6d106fSViresh Kumar 	struct opp_table **required_opp_tables;
1665d6d106fSViresh Kumar 	struct device_node *required_np, *np;
1677eba0c76SViresh Kumar 	bool lazy = false;
168c0ab9e08SViresh Kumar 	int count, i;
1695d6d106fSViresh Kumar 
1705d6d106fSViresh Kumar 	/* Traversing the first OPP node is all we need */
1715d6d106fSViresh Kumar 	np = of_get_next_available_child(opp_np, NULL);
1725d6d106fSViresh Kumar 	if (!np) {
1736ee70e8cSNicola Mazzucato 		dev_warn(dev, "Empty OPP table\n");
1746ee70e8cSNicola Mazzucato 
1755d6d106fSViresh Kumar 		return;
1765d6d106fSViresh Kumar 	}
1775d6d106fSViresh Kumar 
1785d6d106fSViresh Kumar 	count = of_count_phandle_with_args(np, "required-opps", NULL);
1798b7912f4SPavankumar Kondeti 	if (count <= 0)
1805d6d106fSViresh Kumar 		goto put_np;
1815d6d106fSViresh Kumar 
1825d6d106fSViresh Kumar 	required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
1835d6d106fSViresh Kumar 				      GFP_KERNEL);
184c0ab9e08SViresh Kumar 	if (!required_opp_tables)
1855d6d106fSViresh Kumar 		goto put_np;
1865d6d106fSViresh Kumar 
1875d6d106fSViresh Kumar 	opp_table->required_opp_tables = required_opp_tables;
1885d6d106fSViresh Kumar 	opp_table->required_opp_count = count;
1895d6d106fSViresh Kumar 
1905d6d106fSViresh Kumar 	for (i = 0; i < count; i++) {
1915d6d106fSViresh Kumar 		required_np = of_parse_required_opp(np, i);
1925d6d106fSViresh Kumar 		if (!required_np)
1935d6d106fSViresh Kumar 			goto free_required_tables;
1945d6d106fSViresh Kumar 
1955d6d106fSViresh Kumar 		required_opp_tables[i] = _find_table_of_opp_np(required_np);
1965d6d106fSViresh Kumar 		of_node_put(required_np);
1975d6d106fSViresh Kumar 
1984fa82a87SHsin-Yi Wang 		if (IS_ERR(required_opp_tables[i]))
1997eba0c76SViresh Kumar 			lazy = true;
2005d6d106fSViresh Kumar 	}
2015d6d106fSViresh Kumar 
2027eba0c76SViresh Kumar 	/* Let's do the linking later on */
20364aaeb70SViresh Kumar 	if (lazy) {
20464aaeb70SViresh Kumar 		/*
20564aaeb70SViresh Kumar 		 * The OPP table is not held while allocating the table, take it
20664aaeb70SViresh Kumar 		 * now to avoid corruption to the lazy_opp_tables list.
20764aaeb70SViresh Kumar 		 */
20864aaeb70SViresh Kumar 		mutex_lock(&opp_table_lock);
2097eba0c76SViresh Kumar 		list_add(&opp_table->lazy, &lazy_opp_tables);
21064aaeb70SViresh Kumar 		mutex_unlock(&opp_table_lock);
21164aaeb70SViresh Kumar 	}
212528f2d8dSViresh Kumar 	else
213528f2d8dSViresh Kumar 		_update_set_required_opps(opp_table);
2147eba0c76SViresh Kumar 
2155d6d106fSViresh Kumar 	goto put_np;
2165d6d106fSViresh Kumar 
2175d6d106fSViresh Kumar free_required_tables:
2185d6d106fSViresh Kumar 	_opp_table_free_required_tables(opp_table);
2195d6d106fSViresh Kumar put_np:
2205d6d106fSViresh Kumar 	of_node_put(np);
2215d6d106fSViresh Kumar }
2225d6d106fSViresh Kumar 
_of_init_opp_table(struct opp_table * opp_table,struct device * dev,int index)223eb7c8743SViresh Kumar void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
224eb7c8743SViresh Kumar 			int index)
2257813dd6fSViresh Kumar {
226f06ed90eSViresh Kumar 	struct device_node *np, *opp_np;
227f06ed90eSViresh Kumar 	u32 val;
2287813dd6fSViresh Kumar 
2297813dd6fSViresh Kumar 	/*
2307813dd6fSViresh Kumar 	 * Only required for backward compatibility with v1 bindings, but isn't
2317813dd6fSViresh Kumar 	 * harmful for other cases. And so we do it unconditionally.
2327813dd6fSViresh Kumar 	 */
2337813dd6fSViresh Kumar 	np = of_node_get(dev->of_node);
234f06ed90eSViresh Kumar 	if (!np)
235f06ed90eSViresh Kumar 		return;
2367813dd6fSViresh Kumar 
2377813dd6fSViresh Kumar 	if (!of_property_read_u32(np, "clock-latency", &val))
2387813dd6fSViresh Kumar 		opp_table->clock_latency_ns_max = val;
2397813dd6fSViresh Kumar 	of_property_read_u32(np, "voltage-tolerance",
2407813dd6fSViresh Kumar 			     &opp_table->voltage_tolerance_v1);
241f06ed90eSViresh Kumar 
242e9eadc28SRob Herring 	if (of_property_present(np, "#power-domain-cells"))
24361d8e7c7SViresh Kumar 		opp_table->is_genpd = true;
24461d8e7c7SViresh Kumar 
245f06ed90eSViresh Kumar 	/* Get OPP table node */
246f06ed90eSViresh Kumar 	opp_np = _opp_of_get_opp_desc_node(np, index);
2477813dd6fSViresh Kumar 	of_node_put(np);
248f06ed90eSViresh Kumar 
249f06ed90eSViresh Kumar 	if (!opp_np)
250f06ed90eSViresh Kumar 		return;
251f06ed90eSViresh Kumar 
252f06ed90eSViresh Kumar 	if (of_property_read_bool(opp_np, "opp-shared"))
253f06ed90eSViresh Kumar 		opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
254f06ed90eSViresh Kumar 	else
255f06ed90eSViresh Kumar 		opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
256f06ed90eSViresh Kumar 
257f06ed90eSViresh Kumar 	opp_table->np = opp_np;
258f06ed90eSViresh Kumar 
2595d6d106fSViresh Kumar 	_opp_table_alloc_required_tables(opp_table, dev, opp_np);
2607813dd6fSViresh Kumar }
2617813dd6fSViresh Kumar 
_of_clear_opp_table(struct opp_table * opp_table)2625d6d106fSViresh Kumar void _of_clear_opp_table(struct opp_table *opp_table)
2635d6d106fSViresh Kumar {
2645d6d106fSViresh Kumar 	_opp_table_free_required_tables(opp_table);
265ce736cf7SLiang He 	of_node_put(opp_table->np);
2665d6d106fSViresh Kumar }
2675d6d106fSViresh Kumar 
268da544b61SViresh Kumar /*
269da544b61SViresh Kumar  * Release all resources previously acquired with a call to
270da544b61SViresh Kumar  * _of_opp_alloc_required_opps().
271da544b61SViresh Kumar  */
_of_opp_free_required_opps(struct opp_table * opp_table,struct dev_pm_opp * opp)2723466ea2cSLiang He static void _of_opp_free_required_opps(struct opp_table *opp_table,
273da544b61SViresh Kumar 				       struct dev_pm_opp *opp)
274da544b61SViresh Kumar {
275da544b61SViresh Kumar 	struct dev_pm_opp **required_opps = opp->required_opps;
276da544b61SViresh Kumar 	int i;
277da544b61SViresh Kumar 
278da544b61SViresh Kumar 	if (!required_opps)
279da544b61SViresh Kumar 		return;
280da544b61SViresh Kumar 
281da544b61SViresh Kumar 	for (i = 0; i < opp_table->required_opp_count; i++) {
282da544b61SViresh Kumar 		if (!required_opps[i])
2837eba0c76SViresh Kumar 			continue;
284da544b61SViresh Kumar 
285da544b61SViresh Kumar 		/* Put the reference back */
286da544b61SViresh Kumar 		dev_pm_opp_put(required_opps[i]);
287da544b61SViresh Kumar 	}
288da544b61SViresh Kumar 
289da544b61SViresh Kumar 	opp->required_opps = NULL;
2907eba0c76SViresh Kumar 	kfree(required_opps);
291da544b61SViresh Kumar }
292da544b61SViresh Kumar 
_of_clear_opp(struct opp_table * opp_table,struct dev_pm_opp * opp)2933466ea2cSLiang He void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp)
2943466ea2cSLiang He {
2953466ea2cSLiang He 	_of_opp_free_required_opps(opp_table, opp);
2963466ea2cSLiang He 	of_node_put(opp->np);
2973466ea2cSLiang He }
2983466ea2cSLiang He 
299da544b61SViresh Kumar /* Populate all required OPPs which are part of "required-opps" list */
_of_opp_alloc_required_opps(struct opp_table * opp_table,struct dev_pm_opp * opp)300da544b61SViresh Kumar static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
301da544b61SViresh Kumar 				       struct dev_pm_opp *opp)
302da544b61SViresh Kumar {
303da544b61SViresh Kumar 	struct dev_pm_opp **required_opps;
304da544b61SViresh Kumar 	struct opp_table *required_table;
305da544b61SViresh Kumar 	struct device_node *np;
306da544b61SViresh Kumar 	int i, ret, count = opp_table->required_opp_count;
307da544b61SViresh Kumar 
308da544b61SViresh Kumar 	if (!count)
309da544b61SViresh Kumar 		return 0;
310da544b61SViresh Kumar 
311da544b61SViresh Kumar 	required_opps = kcalloc(count, sizeof(*required_opps), GFP_KERNEL);
312da544b61SViresh Kumar 	if (!required_opps)
313da544b61SViresh Kumar 		return -ENOMEM;
314da544b61SViresh Kumar 
315da544b61SViresh Kumar 	opp->required_opps = required_opps;
316da544b61SViresh Kumar 
317da544b61SViresh Kumar 	for (i = 0; i < count; i++) {
318da544b61SViresh Kumar 		required_table = opp_table->required_opp_tables[i];
319da544b61SViresh Kumar 
3207eba0c76SViresh Kumar 		/* Required table not added yet, we will link later */
3217eba0c76SViresh Kumar 		if (IS_ERR_OR_NULL(required_table))
3227eba0c76SViresh Kumar 			continue;
3237eba0c76SViresh Kumar 
324da544b61SViresh Kumar 		np = of_parse_required_opp(opp->np, i);
325da544b61SViresh Kumar 		if (unlikely(!np)) {
326da544b61SViresh Kumar 			ret = -ENODEV;
327da544b61SViresh Kumar 			goto free_required_opps;
328da544b61SViresh Kumar 		}
329da544b61SViresh Kumar 
330da544b61SViresh Kumar 		required_opps[i] = _find_opp_of_np(required_table, np);
331da544b61SViresh Kumar 		of_node_put(np);
332da544b61SViresh Kumar 
333da544b61SViresh Kumar 		if (!required_opps[i]) {
334da544b61SViresh Kumar 			pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
335da544b61SViresh Kumar 			       __func__, opp->np, i);
336da544b61SViresh Kumar 			ret = -ENODEV;
337da544b61SViresh Kumar 			goto free_required_opps;
338da544b61SViresh Kumar 		}
339da544b61SViresh Kumar 	}
340da544b61SViresh Kumar 
341da544b61SViresh Kumar 	return 0;
342da544b61SViresh Kumar 
343da544b61SViresh Kumar free_required_opps:
344da544b61SViresh Kumar 	_of_opp_free_required_opps(opp_table, opp);
345da544b61SViresh Kumar 
346da544b61SViresh Kumar 	return ret;
347da544b61SViresh Kumar }
348da544b61SViresh Kumar 
3497eba0c76SViresh Kumar /* Link required OPPs for an individual OPP */
lazy_link_required_opps(struct opp_table * opp_table,struct opp_table * new_table,int index)3507eba0c76SViresh Kumar static int lazy_link_required_opps(struct opp_table *opp_table,
3517eba0c76SViresh Kumar 				   struct opp_table *new_table, int index)
3527eba0c76SViresh Kumar {
3537eba0c76SViresh Kumar 	struct device_node *required_np;
3547eba0c76SViresh Kumar 	struct dev_pm_opp *opp;
3557eba0c76SViresh Kumar 
3567eba0c76SViresh Kumar 	list_for_each_entry(opp, &opp_table->opp_list, node) {
3577eba0c76SViresh Kumar 		required_np = of_parse_required_opp(opp->np, index);
3587eba0c76SViresh Kumar 		if (unlikely(!required_np))
3597eba0c76SViresh Kumar 			return -ENODEV;
3607eba0c76SViresh Kumar 
3617eba0c76SViresh Kumar 		opp->required_opps[index] = _find_opp_of_np(new_table, required_np);
3627eba0c76SViresh Kumar 		of_node_put(required_np);
3637eba0c76SViresh Kumar 
3647eba0c76SViresh Kumar 		if (!opp->required_opps[index]) {
3657eba0c76SViresh Kumar 			pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
3667eba0c76SViresh Kumar 			       __func__, opp->np, index);
3677eba0c76SViresh Kumar 			return -ENODEV;
3687eba0c76SViresh Kumar 		}
3697eba0c76SViresh Kumar 	}
3707eba0c76SViresh Kumar 
3717eba0c76SViresh Kumar 	return 0;
3727eba0c76SViresh Kumar }
3737eba0c76SViresh Kumar 
3747eba0c76SViresh Kumar /* Link required OPPs for all OPPs of the newly added OPP table */
lazy_link_required_opp_table(struct opp_table * new_table)3757eba0c76SViresh Kumar static void lazy_link_required_opp_table(struct opp_table *new_table)
3767eba0c76SViresh Kumar {
3777eba0c76SViresh Kumar 	struct opp_table *opp_table, *temp, **required_opp_tables;
3787eba0c76SViresh Kumar 	struct device_node *required_np, *opp_np, *required_table_np;
3797eba0c76SViresh Kumar 	struct dev_pm_opp *opp;
3807eba0c76SViresh Kumar 	int i, ret;
3817eba0c76SViresh Kumar 
3827eba0c76SViresh Kumar 	mutex_lock(&opp_table_lock);
3837eba0c76SViresh Kumar 
3847eba0c76SViresh Kumar 	list_for_each_entry_safe(opp_table, temp, &lazy_opp_tables, lazy) {
3857eba0c76SViresh Kumar 		bool lazy = false;
3867eba0c76SViresh Kumar 
3877eba0c76SViresh Kumar 		/* opp_np can't be invalid here */
3887eba0c76SViresh Kumar 		opp_np = of_get_next_available_child(opp_table->np, NULL);
3897eba0c76SViresh Kumar 
3907eba0c76SViresh Kumar 		for (i = 0; i < opp_table->required_opp_count; i++) {
3917eba0c76SViresh Kumar 			required_opp_tables = opp_table->required_opp_tables;
3927eba0c76SViresh Kumar 
3937eba0c76SViresh Kumar 			/* Required opp-table is already parsed */
3947eba0c76SViresh Kumar 			if (!IS_ERR(required_opp_tables[i]))
3957eba0c76SViresh Kumar 				continue;
3967eba0c76SViresh Kumar 
3977eba0c76SViresh Kumar 			/* required_np can't be invalid here */
3987eba0c76SViresh Kumar 			required_np = of_parse_required_opp(opp_np, i);
3997eba0c76SViresh Kumar 			required_table_np = of_get_parent(required_np);
4007eba0c76SViresh Kumar 
4017eba0c76SViresh Kumar 			of_node_put(required_table_np);
4027eba0c76SViresh Kumar 			of_node_put(required_np);
4037eba0c76SViresh Kumar 
4047eba0c76SViresh Kumar 			/*
4057eba0c76SViresh Kumar 			 * Newly added table isn't the required opp-table for
4067eba0c76SViresh Kumar 			 * opp_table.
4077eba0c76SViresh Kumar 			 */
4087eba0c76SViresh Kumar 			if (required_table_np != new_table->np) {
4097eba0c76SViresh Kumar 				lazy = true;
4107eba0c76SViresh Kumar 				continue;
4117eba0c76SViresh Kumar 			}
4127eba0c76SViresh Kumar 
4137eba0c76SViresh Kumar 			required_opp_tables[i] = new_table;
4147eba0c76SViresh Kumar 			_get_opp_table_kref(new_table);
4157eba0c76SViresh Kumar 
4167eba0c76SViresh Kumar 			/* Link OPPs now */
4177eba0c76SViresh Kumar 			ret = lazy_link_required_opps(opp_table, new_table, i);
4187eba0c76SViresh Kumar 			if (ret) {
4197eba0c76SViresh Kumar 				/* The OPPs will be marked unusable */
4207eba0c76SViresh Kumar 				lazy = false;
4217eba0c76SViresh Kumar 				break;
4227eba0c76SViresh Kumar 			}
4237eba0c76SViresh Kumar 		}
4247eba0c76SViresh Kumar 
4257eba0c76SViresh Kumar 		of_node_put(opp_np);
4267eba0c76SViresh Kumar 
4277eba0c76SViresh Kumar 		/* All required opp-tables found, remove from lazy list */
4287eba0c76SViresh Kumar 		if (!lazy) {
429528f2d8dSViresh Kumar 			_update_set_required_opps(opp_table);
430ac9fd3c8SYang Yingliang 			list_del_init(&opp_table->lazy);
4317eba0c76SViresh Kumar 
4327eba0c76SViresh Kumar 			list_for_each_entry(opp, &opp_table->opp_list, node)
4337eba0c76SViresh Kumar 				_required_opps_available(opp, opp_table->required_opp_count);
4347eba0c76SViresh Kumar 		}
4357eba0c76SViresh Kumar 	}
4367eba0c76SViresh Kumar 
4377eba0c76SViresh Kumar 	mutex_unlock(&opp_table_lock);
4387eba0c76SViresh Kumar }
4397eba0c76SViresh Kumar 
_bandwidth_supported(struct device * dev,struct opp_table * opp_table)44045679f9bSSibi Sankar static int _bandwidth_supported(struct device *dev, struct opp_table *opp_table)
44145679f9bSSibi Sankar {
44245679f9bSSibi Sankar 	struct device_node *np, *opp_np;
44345679f9bSSibi Sankar 	struct property *prop;
44445679f9bSSibi Sankar 
44545679f9bSSibi Sankar 	if (!opp_table) {
44645679f9bSSibi Sankar 		np = of_node_get(dev->of_node);
44745679f9bSSibi Sankar 		if (!np)
44845679f9bSSibi Sankar 			return -ENODEV;
44945679f9bSSibi Sankar 
45045679f9bSSibi Sankar 		opp_np = _opp_of_get_opp_desc_node(np, 0);
45145679f9bSSibi Sankar 		of_node_put(np);
45245679f9bSSibi Sankar 	} else {
45345679f9bSSibi Sankar 		opp_np = of_node_get(opp_table->np);
45445679f9bSSibi Sankar 	}
45545679f9bSSibi Sankar 
45645679f9bSSibi Sankar 	/* Lets not fail in case we are parsing opp-v1 bindings */
45745679f9bSSibi Sankar 	if (!opp_np)
45845679f9bSSibi Sankar 		return 0;
45945679f9bSSibi Sankar 
46045679f9bSSibi Sankar 	/* Checking only first OPP is sufficient */
46145679f9bSSibi Sankar 	np = of_get_next_available_child(opp_np, NULL);
462907ed123SDan Carpenter 	of_node_put(opp_np);
46345679f9bSSibi Sankar 	if (!np) {
46445679f9bSSibi Sankar 		dev_err(dev, "OPP table empty\n");
46545679f9bSSibi Sankar 		return -EINVAL;
46645679f9bSSibi Sankar 	}
46745679f9bSSibi Sankar 
46845679f9bSSibi Sankar 	prop = of_find_property(np, "opp-peak-kBps", NULL);
46945679f9bSSibi Sankar 	of_node_put(np);
47045679f9bSSibi Sankar 
47145679f9bSSibi Sankar 	if (!prop || !prop->length)
47245679f9bSSibi Sankar 		return 0;
47345679f9bSSibi Sankar 
47445679f9bSSibi Sankar 	return 1;
47545679f9bSSibi Sankar }
47645679f9bSSibi Sankar 
dev_pm_opp_of_find_icc_paths(struct device * dev,struct opp_table * opp_table)4776d3f922cSGeorgi Djakov int dev_pm_opp_of_find_icc_paths(struct device *dev,
4786d3f922cSGeorgi Djakov 				 struct opp_table *opp_table)
4796d3f922cSGeorgi Djakov {
4806d3f922cSGeorgi Djakov 	struct device_node *np;
48145679f9bSSibi Sankar 	int ret, i, count, num_paths;
4826d3f922cSGeorgi Djakov 	struct icc_path **paths;
4836d3f922cSGeorgi Djakov 
48445679f9bSSibi Sankar 	ret = _bandwidth_supported(dev, opp_table);
4856ee70e8cSNicola Mazzucato 	if (ret == -EINVAL)
4866ee70e8cSNicola Mazzucato 		return 0; /* Empty OPP table is a valid corner-case, let's not fail */
4876ee70e8cSNicola Mazzucato 	else if (ret <= 0)
48845679f9bSSibi Sankar 		return ret;
48945679f9bSSibi Sankar 
49045679f9bSSibi Sankar 	ret = 0;
49145679f9bSSibi Sankar 
4926d3f922cSGeorgi Djakov 	np = of_node_get(dev->of_node);
4936d3f922cSGeorgi Djakov 	if (!np)
4946d3f922cSGeorgi Djakov 		return 0;
4956d3f922cSGeorgi Djakov 
4966d3f922cSGeorgi Djakov 	count = of_count_phandle_with_args(np, "interconnects",
4976d3f922cSGeorgi Djakov 					   "#interconnect-cells");
4986d3f922cSGeorgi Djakov 	of_node_put(np);
4996d3f922cSGeorgi Djakov 	if (count < 0)
5006d3f922cSGeorgi Djakov 		return 0;
5016d3f922cSGeorgi Djakov 
5026d3f922cSGeorgi Djakov 	/* two phandles when #interconnect-cells = <1> */
5036d3f922cSGeorgi Djakov 	if (count % 2) {
5046d3f922cSGeorgi Djakov 		dev_err(dev, "%s: Invalid interconnects values\n", __func__);
5056d3f922cSGeorgi Djakov 		return -EINVAL;
5066d3f922cSGeorgi Djakov 	}
5076d3f922cSGeorgi Djakov 
5086d3f922cSGeorgi Djakov 	num_paths = count / 2;
5096d3f922cSGeorgi Djakov 	paths = kcalloc(num_paths, sizeof(*paths), GFP_KERNEL);
5106d3f922cSGeorgi Djakov 	if (!paths)
5116d3f922cSGeorgi Djakov 		return -ENOMEM;
5126d3f922cSGeorgi Djakov 
5136d3f922cSGeorgi Djakov 	for (i = 0; i < num_paths; i++) {
5146d3f922cSGeorgi Djakov 		paths[i] = of_icc_get_by_index(dev, i);
5156d3f922cSGeorgi Djakov 		if (IS_ERR(paths[i])) {
5165fb2864cSAndrew Halaney 			ret = dev_err_probe(dev, PTR_ERR(paths[i]), "%s: Unable to get path%d\n", __func__, i);
5176d3f922cSGeorgi Djakov 			goto err;
5186d3f922cSGeorgi Djakov 		}
5196d3f922cSGeorgi Djakov 	}
5206d3f922cSGeorgi Djakov 
5216d3f922cSGeorgi Djakov 	if (opp_table) {
5226d3f922cSGeorgi Djakov 		opp_table->paths = paths;
5236d3f922cSGeorgi Djakov 		opp_table->path_count = num_paths;
5246d3f922cSGeorgi Djakov 		return 0;
5256d3f922cSGeorgi Djakov 	}
5266d3f922cSGeorgi Djakov 
5276d3f922cSGeorgi Djakov err:
5286d3f922cSGeorgi Djakov 	while (i--)
5296d3f922cSGeorgi Djakov 		icc_put(paths[i]);
5306d3f922cSGeorgi Djakov 
5316d3f922cSGeorgi Djakov 	kfree(paths);
5326d3f922cSGeorgi Djakov 
5336d3f922cSGeorgi Djakov 	return ret;
5346d3f922cSGeorgi Djakov }
5356d3f922cSGeorgi Djakov EXPORT_SYMBOL_GPL(dev_pm_opp_of_find_icc_paths);
5366d3f922cSGeorgi Djakov 
_opp_is_supported(struct device * dev,struct opp_table * opp_table,struct device_node * np)5377813dd6fSViresh Kumar static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
5387813dd6fSViresh Kumar 			      struct device_node *np)
5397813dd6fSViresh Kumar {
5400ff25c99SViresh Kumar 	unsigned int levels = opp_table->supported_hw_count;
5410ff25c99SViresh Kumar 	int count, versions, ret, i, j;
5420ff25c99SViresh Kumar 	u32 val;
5437813dd6fSViresh Kumar 
5447813dd6fSViresh Kumar 	if (!opp_table->supported_hw) {
5457813dd6fSViresh Kumar 		/*
5467813dd6fSViresh Kumar 		 * In the case that no supported_hw has been set by the
5477813dd6fSViresh Kumar 		 * platform but there is an opp-supported-hw value set for
5487813dd6fSViresh Kumar 		 * an OPP then the OPP should not be enabled as there is
5497813dd6fSViresh Kumar 		 * no way to see if the hardware supports it.
5507813dd6fSViresh Kumar 		 */
551e9eadc28SRob Herring 		if (of_property_present(np, "opp-supported-hw"))
5527813dd6fSViresh Kumar 			return false;
5537813dd6fSViresh Kumar 		else
5547813dd6fSViresh Kumar 			return true;
5557813dd6fSViresh Kumar 	}
5567813dd6fSViresh Kumar 
5570ff25c99SViresh Kumar 	count = of_property_count_u32_elems(np, "opp-supported-hw");
5580ff25c99SViresh Kumar 	if (count <= 0 || count % levels) {
5590ff25c99SViresh Kumar 		dev_err(dev, "%s: Invalid opp-supported-hw property (%d)\n",
5600ff25c99SViresh Kumar 			__func__, count);
5610ff25c99SViresh Kumar 		return false;
5620ff25c99SViresh Kumar 	}
5630ff25c99SViresh Kumar 
5640ff25c99SViresh Kumar 	versions = count / levels;
5650ff25c99SViresh Kumar 
5660ff25c99SViresh Kumar 	/* All levels in at least one of the versions should match */
5670ff25c99SViresh Kumar 	for (i = 0; i < versions; i++) {
5680ff25c99SViresh Kumar 		bool supported = true;
5690ff25c99SViresh Kumar 
5700ff25c99SViresh Kumar 		for (j = 0; j < levels; j++) {
5710ff25c99SViresh Kumar 			ret = of_property_read_u32_index(np, "opp-supported-hw",
5720ff25c99SViresh Kumar 							 i * levels + j, &val);
5737813dd6fSViresh Kumar 			if (ret) {
5747813dd6fSViresh Kumar 				dev_warn(dev, "%s: failed to read opp-supported-hw property at index %d: %d\n",
5750ff25c99SViresh Kumar 					 __func__, i * levels + j, ret);
5767813dd6fSViresh Kumar 				return false;
5777813dd6fSViresh Kumar 			}
5787813dd6fSViresh Kumar 
5790ff25c99SViresh Kumar 			/* Check if the level is supported */
5800ff25c99SViresh Kumar 			if (!(val & opp_table->supported_hw[j])) {
5810ff25c99SViresh Kumar 				supported = false;
5820ff25c99SViresh Kumar 				break;
5830ff25c99SViresh Kumar 			}
5847813dd6fSViresh Kumar 		}
5857813dd6fSViresh Kumar 
5860ff25c99SViresh Kumar 		if (supported)
5877813dd6fSViresh Kumar 			return true;
5887813dd6fSViresh Kumar 	}
5897813dd6fSViresh Kumar 
5900ff25c99SViresh Kumar 	return false;
5910ff25c99SViresh Kumar }
5920ff25c99SViresh Kumar 
_parse_named_prop(struct dev_pm_opp * opp,struct device * dev,struct opp_table * opp_table,const char * prop_type,bool * triplet)593e5acb199SViresh Kumar static u32 *_parse_named_prop(struct dev_pm_opp *opp, struct device *dev,
594e5acb199SViresh Kumar 			      struct opp_table *opp_table,
595e5acb199SViresh Kumar 			      const char *prop_type, bool *triplet)
596e5acb199SViresh Kumar {
597e5acb199SViresh Kumar 	struct property *prop = NULL;
598e5acb199SViresh Kumar 	char name[NAME_MAX];
599e5acb199SViresh Kumar 	int count, ret;
600e5acb199SViresh Kumar 	u32 *out;
601e5acb199SViresh Kumar 
602e5acb199SViresh Kumar 	/* Search for "opp-<prop_type>-<name>" */
603e5acb199SViresh Kumar 	if (opp_table->prop_name) {
604e5acb199SViresh Kumar 		snprintf(name, sizeof(name), "opp-%s-%s", prop_type,
605e5acb199SViresh Kumar 			 opp_table->prop_name);
606e5acb199SViresh Kumar 		prop = of_find_property(opp->np, name, NULL);
607e5acb199SViresh Kumar 	}
608e5acb199SViresh Kumar 
609e5acb199SViresh Kumar 	if (!prop) {
610e5acb199SViresh Kumar 		/* Search for "opp-<prop_type>" */
611e5acb199SViresh Kumar 		snprintf(name, sizeof(name), "opp-%s", prop_type);
612e5acb199SViresh Kumar 		prop = of_find_property(opp->np, name, NULL);
613e5acb199SViresh Kumar 		if (!prop)
614e5acb199SViresh Kumar 			return NULL;
615e5acb199SViresh Kumar 	}
616e5acb199SViresh Kumar 
617e5acb199SViresh Kumar 	count = of_property_count_u32_elems(opp->np, name);
618e5acb199SViresh Kumar 	if (count < 0) {
619e5acb199SViresh Kumar 		dev_err(dev, "%s: Invalid %s property (%d)\n", __func__, name,
620e5acb199SViresh Kumar 			count);
621e5acb199SViresh Kumar 		return ERR_PTR(count);
622e5acb199SViresh Kumar 	}
623e5acb199SViresh Kumar 
624e5acb199SViresh Kumar 	/*
625e5acb199SViresh Kumar 	 * Initialize regulator_count, if regulator information isn't provided
626e5acb199SViresh Kumar 	 * by the platform. Now that one of the properties is available, fix the
627e5acb199SViresh Kumar 	 * regulator_count to 1.
628e5acb199SViresh Kumar 	 */
629e5acb199SViresh Kumar 	if (unlikely(opp_table->regulator_count == -1))
630e5acb199SViresh Kumar 		opp_table->regulator_count = 1;
631e5acb199SViresh Kumar 
632e5acb199SViresh Kumar 	if (count != opp_table->regulator_count &&
633e5acb199SViresh Kumar 	    (!triplet || count != opp_table->regulator_count * 3)) {
634e5acb199SViresh Kumar 		dev_err(dev, "%s: Invalid number of elements in %s property (%u) with supplies (%d)\n",
635e5acb199SViresh Kumar 			__func__, prop_type, count, opp_table->regulator_count);
636e5acb199SViresh Kumar 		return ERR_PTR(-EINVAL);
637e5acb199SViresh Kumar 	}
638e5acb199SViresh Kumar 
639e5acb199SViresh Kumar 	out = kmalloc_array(count, sizeof(*out), GFP_KERNEL);
640e5acb199SViresh Kumar 	if (!out)
641e5acb199SViresh Kumar 		return ERR_PTR(-EINVAL);
642e5acb199SViresh Kumar 
643e5acb199SViresh Kumar 	ret = of_property_read_u32_array(opp->np, name, out, count);
644e5acb199SViresh Kumar 	if (ret) {
645e5acb199SViresh Kumar 		dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
646e5acb199SViresh Kumar 		kfree(out);
647e5acb199SViresh Kumar 		return ERR_PTR(-EINVAL);
648e5acb199SViresh Kumar 	}
649e5acb199SViresh Kumar 
650e5acb199SViresh Kumar 	if (triplet)
651e5acb199SViresh Kumar 		*triplet = count != opp_table->regulator_count;
652e5acb199SViresh Kumar 
653e5acb199SViresh Kumar 	return out;
654e5acb199SViresh Kumar }
655e5acb199SViresh Kumar 
opp_parse_microvolt(struct dev_pm_opp * opp,struct device * dev,struct opp_table * opp_table,bool * triplet)656e5acb199SViresh Kumar static u32 *opp_parse_microvolt(struct dev_pm_opp *opp, struct device *dev,
657e5acb199SViresh Kumar 				struct opp_table *opp_table, bool *triplet)
658e5acb199SViresh Kumar {
659e5acb199SViresh Kumar 	u32 *microvolt;
660e5acb199SViresh Kumar 
661e5acb199SViresh Kumar 	microvolt = _parse_named_prop(opp, dev, opp_table, "microvolt", triplet);
662e5acb199SViresh Kumar 	if (IS_ERR(microvolt))
663e5acb199SViresh Kumar 		return microvolt;
664e5acb199SViresh Kumar 
665e5acb199SViresh Kumar 	if (!microvolt) {
666e5acb199SViresh Kumar 		/*
667e5acb199SViresh Kumar 		 * Missing property isn't a problem, but an invalid
668e5acb199SViresh Kumar 		 * entry is. This property isn't optional if regulator
6692eedf62eSJames Calligeros 		 * information is provided. Check only for the first OPP, as
6702eedf62eSJames Calligeros 		 * regulator_count may get initialized after that to a valid
6712eedf62eSJames Calligeros 		 * value.
672e5acb199SViresh Kumar 		 */
6732eedf62eSJames Calligeros 		if (list_empty(&opp_table->opp_list) &&
6742eedf62eSJames Calligeros 		    opp_table->regulator_count > 0) {
675e5acb199SViresh Kumar 			dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
676e5acb199SViresh Kumar 				__func__);
677e5acb199SViresh Kumar 			return ERR_PTR(-EINVAL);
678e5acb199SViresh Kumar 		}
679e5acb199SViresh Kumar 	}
680e5acb199SViresh Kumar 
681e5acb199SViresh Kumar 	return microvolt;
682e5acb199SViresh Kumar }
683e5acb199SViresh Kumar 
opp_parse_supplies(struct dev_pm_opp * opp,struct device * dev,struct opp_table * opp_table)6847813dd6fSViresh Kumar static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
6857813dd6fSViresh Kumar 			      struct opp_table *opp_table)
6867813dd6fSViresh Kumar {
687e5acb199SViresh Kumar 	u32 *microvolt, *microamp, *microwatt;
688e5acb199SViresh Kumar 	int ret = 0, i, j;
689e5acb199SViresh Kumar 	bool triplet;
6907813dd6fSViresh Kumar 
691e5acb199SViresh Kumar 	microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
6922eedf62eSJames Calligeros 	if (IS_ERR(microvolt))
693e5acb199SViresh Kumar 		return PTR_ERR(microvolt);
6947813dd6fSViresh Kumar 
695e5acb199SViresh Kumar 	microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
696e5acb199SViresh Kumar 	if (IS_ERR(microamp)) {
697e5acb199SViresh Kumar 		ret = PTR_ERR(microamp);
6987813dd6fSViresh Kumar 		goto free_microvolt;
6997813dd6fSViresh Kumar 	}
7007813dd6fSViresh Kumar 
701e5acb199SViresh Kumar 	microwatt = _parse_named_prop(opp, dev, opp_table, "microwatt", NULL);
702e5acb199SViresh Kumar 	if (IS_ERR(microwatt)) {
703e5acb199SViresh Kumar 		ret = PTR_ERR(microwatt);
7044f9a7a1dSLukasz Luba 		goto free_microamp;
7054f9a7a1dSLukasz Luba 	}
7064f9a7a1dSLukasz Luba 
7072eedf62eSJames Calligeros 	/*
7082eedf62eSJames Calligeros 	 * Initialize regulator_count if it is uninitialized and no properties
7092eedf62eSJames Calligeros 	 * are found.
7102eedf62eSJames Calligeros 	 */
7112eedf62eSJames Calligeros 	if (unlikely(opp_table->regulator_count == -1)) {
7122eedf62eSJames Calligeros 		opp_table->regulator_count = 0;
7132eedf62eSJames Calligeros 		return 0;
7142eedf62eSJames Calligeros 	}
7152eedf62eSJames Calligeros 
716e5acb199SViresh Kumar 	for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
7172eedf62eSJames Calligeros 		if (microvolt) {
7187813dd6fSViresh Kumar 			opp->supplies[i].u_volt = microvolt[j++];
7197813dd6fSViresh Kumar 
720e5acb199SViresh Kumar 			if (triplet) {
7217813dd6fSViresh Kumar 				opp->supplies[i].u_volt_min = microvolt[j++];
7227813dd6fSViresh Kumar 				opp->supplies[i].u_volt_max = microvolt[j++];
723e5acb199SViresh Kumar 			} else {
724e5acb199SViresh Kumar 				opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
725e5acb199SViresh Kumar 				opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
7267813dd6fSViresh Kumar 			}
7272eedf62eSJames Calligeros 		}
7287813dd6fSViresh Kumar 
7297813dd6fSViresh Kumar 		if (microamp)
7307813dd6fSViresh Kumar 			opp->supplies[i].u_amp = microamp[i];
7314f9a7a1dSLukasz Luba 
7324f9a7a1dSLukasz Luba 		if (microwatt)
7334f9a7a1dSLukasz Luba 			opp->supplies[i].u_watt = microwatt[i];
7347813dd6fSViresh Kumar 	}
7357813dd6fSViresh Kumar 
7364f9a7a1dSLukasz Luba 	kfree(microwatt);
7377813dd6fSViresh Kumar free_microamp:
7387813dd6fSViresh Kumar 	kfree(microamp);
7397813dd6fSViresh Kumar free_microvolt:
7407813dd6fSViresh Kumar 	kfree(microvolt);
7417813dd6fSViresh Kumar 
7427813dd6fSViresh Kumar 	return ret;
7437813dd6fSViresh Kumar }
7447813dd6fSViresh Kumar 
7457813dd6fSViresh Kumar /**
7467813dd6fSViresh Kumar  * dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT
7477813dd6fSViresh Kumar  *				  entries
7487813dd6fSViresh Kumar  * @dev:	device pointer used to lookup OPP table.
7497813dd6fSViresh Kumar  *
7507813dd6fSViresh Kumar  * Free OPPs created using static entries present in DT.
7517813dd6fSViresh Kumar  */
dev_pm_opp_of_remove_table(struct device * dev)7527813dd6fSViresh Kumar void dev_pm_opp_of_remove_table(struct device *dev)
7537813dd6fSViresh Kumar {
7548aaf6264SViresh Kumar 	dev_pm_opp_remove_table(dev);
7557813dd6fSViresh Kumar }
7567813dd6fSViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
7577813dd6fSViresh Kumar 
_read_rate(struct dev_pm_opp * new_opp,struct opp_table * opp_table,struct device_node * np)7582083da24SViresh Kumar static int _read_rate(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
7592083da24SViresh Kumar 		      struct device_node *np)
7602083da24SViresh Kumar {
7612083da24SViresh Kumar 	struct property *prop;
7622083da24SViresh Kumar 	int i, count, ret;
7632083da24SViresh Kumar 	u64 *rates;
7642083da24SViresh Kumar 
7652083da24SViresh Kumar 	prop = of_find_property(np, "opp-hz", NULL);
7662083da24SViresh Kumar 	if (!prop)
7672083da24SViresh Kumar 		return -ENODEV;
7682083da24SViresh Kumar 
7692083da24SViresh Kumar 	count = prop->length / sizeof(u64);
7702083da24SViresh Kumar 	if (opp_table->clk_count != count) {
7712083da24SViresh Kumar 		pr_err("%s: Count mismatch between opp-hz and clk_count (%d %d)\n",
7722083da24SViresh Kumar 		       __func__, count, opp_table->clk_count);
7732083da24SViresh Kumar 		return -EINVAL;
7742083da24SViresh Kumar 	}
7752083da24SViresh Kumar 
7762083da24SViresh Kumar 	rates = kmalloc_array(count, sizeof(*rates), GFP_KERNEL);
7772083da24SViresh Kumar 	if (!rates)
7782083da24SViresh Kumar 		return -ENOMEM;
7792083da24SViresh Kumar 
7802083da24SViresh Kumar 	ret = of_property_read_u64_array(np, "opp-hz", rates, count);
7812083da24SViresh Kumar 	if (ret) {
7822083da24SViresh Kumar 		pr_err("%s: Error parsing opp-hz: %d\n", __func__, ret);
7832083da24SViresh Kumar 	} else {
7842083da24SViresh Kumar 		/*
7852083da24SViresh Kumar 		 * Rate is defined as an unsigned long in clk API, and so
7862083da24SViresh Kumar 		 * casting explicitly to its type. Must be fixed once rate is 64
7872083da24SViresh Kumar 		 * bit guaranteed in clk API.
7882083da24SViresh Kumar 		 */
7892083da24SViresh Kumar 		for (i = 0; i < count; i++) {
7902083da24SViresh Kumar 			new_opp->rates[i] = (unsigned long)rates[i];
7912083da24SViresh Kumar 
7922083da24SViresh Kumar 			/* This will happen for frequencies > 4.29 GHz */
7932083da24SViresh Kumar 			WARN_ON(new_opp->rates[i] != rates[i]);
7942083da24SViresh Kumar 		}
7952083da24SViresh Kumar 	}
7962083da24SViresh Kumar 
7972083da24SViresh Kumar 	kfree(rates);
7982083da24SViresh Kumar 
7992083da24SViresh Kumar 	return ret;
8002083da24SViresh Kumar }
8012083da24SViresh Kumar 
_read_bw(struct dev_pm_opp * new_opp,struct opp_table * opp_table,struct device_node * np,bool peak)802d6134583SViresh Kumar static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *opp_table,
803120e117bSGeorgi Djakov 		    struct device_node *np, bool peak)
8046d3f922cSGeorgi Djakov {
8056d3f922cSGeorgi Djakov 	const char *name = peak ? "opp-peak-kBps" : "opp-avg-kBps";
8066d3f922cSGeorgi Djakov 	struct property *prop;
8076d3f922cSGeorgi Djakov 	int i, count, ret;
8086d3f922cSGeorgi Djakov 	u32 *bw;
8096d3f922cSGeorgi Djakov 
8106d3f922cSGeorgi Djakov 	prop = of_find_property(np, name, NULL);
8116d3f922cSGeorgi Djakov 	if (!prop)
8126d3f922cSGeorgi Djakov 		return -ENODEV;
8136d3f922cSGeorgi Djakov 
8146d3f922cSGeorgi Djakov 	count = prop->length / sizeof(u32);
815d6134583SViresh Kumar 	if (opp_table->path_count != count) {
816120e117bSGeorgi Djakov 		pr_err("%s: Mismatch between %s and paths (%d %d)\n",
817d6134583SViresh Kumar 				__func__, name, count, opp_table->path_count);
818120e117bSGeorgi Djakov 		return -EINVAL;
819120e117bSGeorgi Djakov 	}
820120e117bSGeorgi Djakov 
8216d3f922cSGeorgi Djakov 	bw = kmalloc_array(count, sizeof(*bw), GFP_KERNEL);
8226d3f922cSGeorgi Djakov 	if (!bw)
8236d3f922cSGeorgi Djakov 		return -ENOMEM;
8246d3f922cSGeorgi Djakov 
8256d3f922cSGeorgi Djakov 	ret = of_property_read_u32_array(np, name, bw, count);
8266d3f922cSGeorgi Djakov 	if (ret) {
8276d3f922cSGeorgi Djakov 		pr_err("%s: Error parsing %s: %d\n", __func__, name, ret);
8286d3f922cSGeorgi Djakov 		goto out;
8296d3f922cSGeorgi Djakov 	}
8306d3f922cSGeorgi Djakov 
8316d3f922cSGeorgi Djakov 	for (i = 0; i < count; i++) {
8326d3f922cSGeorgi Djakov 		if (peak)
8336d3f922cSGeorgi Djakov 			new_opp->bandwidth[i].peak = kBps_to_icc(bw[i]);
8346d3f922cSGeorgi Djakov 		else
8356d3f922cSGeorgi Djakov 			new_opp->bandwidth[i].avg = kBps_to_icc(bw[i]);
8366d3f922cSGeorgi Djakov 	}
8376d3f922cSGeorgi Djakov 
8386d3f922cSGeorgi Djakov out:
8396d3f922cSGeorgi Djakov 	kfree(bw);
8406d3f922cSGeorgi Djakov 	return ret;
8416d3f922cSGeorgi Djakov }
8426d3f922cSGeorgi Djakov 
_read_opp_key(struct dev_pm_opp * new_opp,struct opp_table * opp_table,struct device_node * np)8434768914bSViresh Kumar static int _read_opp_key(struct dev_pm_opp *new_opp,
8444768914bSViresh Kumar 			 struct opp_table *opp_table, struct device_node *np)
8456c591eecSSaravana Kannan {
8466d3f922cSGeorgi Djakov 	bool found = false;
8476c591eecSSaravana Kannan 	int ret;
8486c591eecSSaravana Kannan 
8492083da24SViresh Kumar 	ret = _read_rate(new_opp, opp_table, np);
8502083da24SViresh Kumar 	if (!ret)
8516d3f922cSGeorgi Djakov 		found = true;
8522083da24SViresh Kumar 	else if (ret != -ENODEV)
8532083da24SViresh Kumar 		return ret;
8546c591eecSSaravana Kannan 
8556d3f922cSGeorgi Djakov 	/*
8566d3f922cSGeorgi Djakov 	 * Bandwidth consists of peak and average (optional) values:
8576d3f922cSGeorgi Djakov 	 * opp-peak-kBps = <path1_value path2_value>;
8586d3f922cSGeorgi Djakov 	 * opp-avg-kBps = <path1_value path2_value>;
8596d3f922cSGeorgi Djakov 	 */
860d6134583SViresh Kumar 	ret = _read_bw(new_opp, opp_table, np, true);
8616d3f922cSGeorgi Djakov 	if (!ret) {
8626d3f922cSGeorgi Djakov 		found = true;
863d6134583SViresh Kumar 		ret = _read_bw(new_opp, opp_table, np, false);
8646d3f922cSGeorgi Djakov 	}
8656d3f922cSGeorgi Djakov 
8666d3f922cSGeorgi Djakov 	/* The properties were found but we failed to parse them */
8676d3f922cSGeorgi Djakov 	if (ret && ret != -ENODEV)
8686d3f922cSGeorgi Djakov 		return ret;
8696d3f922cSGeorgi Djakov 
8706d3f922cSGeorgi Djakov 	if (!of_property_read_u32(np, "opp-level", &new_opp->level))
8716d3f922cSGeorgi Djakov 		found = true;
8726d3f922cSGeorgi Djakov 
8736d3f922cSGeorgi Djakov 	if (found)
8746d3f922cSGeorgi Djakov 		return 0;
8756c591eecSSaravana Kannan 
8766c591eecSSaravana Kannan 	return ret;
8776c591eecSSaravana Kannan }
8786c591eecSSaravana Kannan 
8797813dd6fSViresh Kumar /**
8807813dd6fSViresh Kumar  * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
8817813dd6fSViresh Kumar  * @opp_table:	OPP table
8827813dd6fSViresh Kumar  * @dev:	device for which we do this operation
8837813dd6fSViresh Kumar  * @np:		device node
8847813dd6fSViresh Kumar  *
8857813dd6fSViresh Kumar  * This function adds an opp definition to the opp table and returns status. The
8867813dd6fSViresh Kumar  * opp can be controlled using dev_pm_opp_enable/disable functions and may be
8877813dd6fSViresh Kumar  * removed by dev_pm_opp_remove.
8887813dd6fSViresh Kumar  *
8897813dd6fSViresh Kumar  * Return:
890deac8703SDave Gerlach  * Valid OPP pointer:
891deac8703SDave Gerlach  *		On success
892deac8703SDave Gerlach  * NULL:
8937813dd6fSViresh Kumar  *		Duplicate OPPs (both freq and volt are same) and opp->available
894deac8703SDave Gerlach  *		OR if the OPP is not supported by hardware.
895deac8703SDave Gerlach  * ERR_PTR(-EEXIST):
896deac8703SDave Gerlach  *		Freq are same and volt are different OR
8977813dd6fSViresh Kumar  *		Duplicate OPPs (both freq and volt are same) and !opp->available
898deac8703SDave Gerlach  * ERR_PTR(-ENOMEM):
899deac8703SDave Gerlach  *		Memory allocation failure
900deac8703SDave Gerlach  * ERR_PTR(-EINVAL):
901deac8703SDave Gerlach  *		Failed parsing the OPP node
9027813dd6fSViresh Kumar  */
_opp_add_static_v2(struct opp_table * opp_table,struct device * dev,struct device_node * np)903deac8703SDave Gerlach static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
904deac8703SDave Gerlach 		struct device *dev, struct device_node *np)
9057813dd6fSViresh Kumar {
9067813dd6fSViresh Kumar 	struct dev_pm_opp *new_opp;
9077813dd6fSViresh Kumar 	u32 val;
9087813dd6fSViresh Kumar 	int ret;
9097813dd6fSViresh Kumar 
9107813dd6fSViresh Kumar 	new_opp = _opp_allocate(opp_table);
9117813dd6fSViresh Kumar 	if (!new_opp)
912deac8703SDave Gerlach 		return ERR_PTR(-ENOMEM);
9137813dd6fSViresh Kumar 
9144768914bSViresh Kumar 	ret = _read_opp_key(new_opp, opp_table, np);
9154fa82a87SHsin-Yi Wang 	if (ret < 0) {
9166c591eecSSaravana Kannan 		dev_err(dev, "%s: opp key field not found\n", __func__);
9177813dd6fSViresh Kumar 		goto free_opp;
9187813dd6fSViresh Kumar 	}
9197813dd6fSViresh Kumar 
9207813dd6fSViresh Kumar 	/* Check if the OPP supports hardware's hierarchy of versions or not */
9217813dd6fSViresh Kumar 	if (!_opp_is_supported(dev, opp_table, np)) {
9222083da24SViresh Kumar 		dev_dbg(dev, "OPP not supported by hardware: %s\n",
9232083da24SViresh Kumar 			of_node_full_name(np));
9247813dd6fSViresh Kumar 		goto free_opp;
9257813dd6fSViresh Kumar 	}
9267813dd6fSViresh Kumar 
9277813dd6fSViresh Kumar 	new_opp->turbo = of_property_read_bool(np, "turbo-mode");
9287813dd6fSViresh Kumar 
9293466ea2cSLiang He 	new_opp->np = of_node_get(np);
9307813dd6fSViresh Kumar 	new_opp->dynamic = false;
9317813dd6fSViresh Kumar 	new_opp->available = true;
9327813dd6fSViresh Kumar 
933da544b61SViresh Kumar 	ret = _of_opp_alloc_required_opps(opp_table, new_opp);
934da544b61SViresh Kumar 	if (ret)
935*7ec98ebbSJoe Hattori 		goto put_node;
936da544b61SViresh Kumar 
9377813dd6fSViresh Kumar 	if (!of_property_read_u32(np, "clock-latency-ns", &val))
9387813dd6fSViresh Kumar 		new_opp->clock_latency_ns = val;
9397813dd6fSViresh Kumar 
9407813dd6fSViresh Kumar 	ret = opp_parse_supplies(new_opp, dev, opp_table);
9417813dd6fSViresh Kumar 	if (ret)
942da544b61SViresh Kumar 		goto free_required_opps;
9437813dd6fSViresh Kumar 
9444768914bSViresh Kumar 	ret = _opp_add(dev, new_opp, opp_table);
9457813dd6fSViresh Kumar 	if (ret) {
9467813dd6fSViresh Kumar 		/* Don't return error for duplicate OPPs */
9477813dd6fSViresh Kumar 		if (ret == -EBUSY)
9487813dd6fSViresh Kumar 			ret = 0;
949da544b61SViresh Kumar 		goto free_required_opps;
9507813dd6fSViresh Kumar 	}
9517813dd6fSViresh Kumar 
9527813dd6fSViresh Kumar 	/* OPP to select on device suspend */
9537813dd6fSViresh Kumar 	if (of_property_read_bool(np, "opp-suspend")) {
9547813dd6fSViresh Kumar 		if (opp_table->suspend_opp) {
9558bdac14bSViresh Kumar 			/* Pick the OPP with higher rate/bw/level as suspend OPP */
9562083da24SViresh Kumar 			if (_opp_compare_key(opp_table, new_opp, opp_table->suspend_opp) == 1) {
95745275517SAnson Huang 				opp_table->suspend_opp->suspend = false;
95845275517SAnson Huang 				new_opp->suspend = true;
95945275517SAnson Huang 				opp_table->suspend_opp = new_opp;
96045275517SAnson Huang 			}
9617813dd6fSViresh Kumar 		} else {
9627813dd6fSViresh Kumar 			new_opp->suspend = true;
9637813dd6fSViresh Kumar 			opp_table->suspend_opp = new_opp;
9647813dd6fSViresh Kumar 		}
9657813dd6fSViresh Kumar 	}
9667813dd6fSViresh Kumar 
9677813dd6fSViresh Kumar 	if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
9687813dd6fSViresh Kumar 		opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
9697813dd6fSViresh Kumar 
970b6ecd5d4SDmitry Osipenko 	pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu level:%u\n",
9712083da24SViresh Kumar 		 __func__, new_opp->turbo, new_opp->rates[0],
9727813dd6fSViresh Kumar 		 new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
973b6ecd5d4SDmitry Osipenko 		 new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns,
974b6ecd5d4SDmitry Osipenko 		 new_opp->level);
9757813dd6fSViresh Kumar 
9767813dd6fSViresh Kumar 	/*
9777813dd6fSViresh Kumar 	 * Notify the changes in the availability of the operable
9787813dd6fSViresh Kumar 	 * frequency/voltage list.
9797813dd6fSViresh Kumar 	 */
9807813dd6fSViresh Kumar 	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
981deac8703SDave Gerlach 	return new_opp;
9827813dd6fSViresh Kumar 
983da544b61SViresh Kumar free_required_opps:
984da544b61SViresh Kumar 	_of_opp_free_required_opps(opp_table, new_opp);
985*7ec98ebbSJoe Hattori put_node:
986*7ec98ebbSJoe Hattori 	of_node_put(np);
9877813dd6fSViresh Kumar free_opp:
9887813dd6fSViresh Kumar 	_opp_free(new_opp);
9897813dd6fSViresh Kumar 
99027ff8187SYueHaibing 	return ret ? ERR_PTR(ret) : NULL;
9917813dd6fSViresh Kumar }
9927813dd6fSViresh Kumar 
9937813dd6fSViresh Kumar /* Initializes OPP tables based on new bindings */
_of_add_opp_table_v2(struct device * dev,struct opp_table * opp_table)9945ed4cecdSViresh Kumar static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
9957813dd6fSViresh Kumar {
9967813dd6fSViresh Kumar 	struct device_node *np;
997a5663c9bSViresh Kumar 	int ret, count = 0;
9983ba98324SViresh Kumar 	struct dev_pm_opp *opp;
9997813dd6fSViresh Kumar 
1000283d55e6SViresh Kumar 	/* OPP table is already initialized for the device */
100103758d60SViresh Kumar 	mutex_lock(&opp_table->lock);
1002283d55e6SViresh Kumar 	if (opp_table->parsed_static_opps) {
100303758d60SViresh Kumar 		opp_table->parsed_static_opps++;
100403758d60SViresh Kumar 		mutex_unlock(&opp_table->lock);
1005283d55e6SViresh Kumar 		return 0;
1006283d55e6SViresh Kumar 	}
1007283d55e6SViresh Kumar 
100803758d60SViresh Kumar 	opp_table->parsed_static_opps = 1;
100903758d60SViresh Kumar 	mutex_unlock(&opp_table->lock);
1010b19c2355SViresh Kumar 
10117813dd6fSViresh Kumar 	/* We have opp-table node now, iterate over it and add OPPs */
10125ed4cecdSViresh Kumar 	for_each_available_child_of_node(opp_table->np, np) {
1013deac8703SDave Gerlach 		opp = _opp_add_static_v2(opp_table, dev, np);
1014deac8703SDave Gerlach 		if (IS_ERR(opp)) {
1015deac8703SDave Gerlach 			ret = PTR_ERR(opp);
10167813dd6fSViresh Kumar 			dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
10177813dd6fSViresh Kumar 				ret);
10187978db34STobias Jordan 			of_node_put(np);
101903758d60SViresh Kumar 			goto remove_static_opp;
1020deac8703SDave Gerlach 		} else if (opp) {
1021deac8703SDave Gerlach 			count++;
10227813dd6fSViresh Kumar 		}
10237813dd6fSViresh Kumar 	}
10247813dd6fSViresh Kumar 
1025335ffab3SMichał Mirosław 	/* There should be one or more OPPs defined */
1026335ffab3SMichał Mirosław 	if (!count) {
1027335ffab3SMichał Mirosław 		dev_err(dev, "%s: no supported OPPs", __func__);
1028ba003319SViresh Kumar 		ret = -ENOENT;
102903758d60SViresh Kumar 		goto remove_static_opp;
1030ba003319SViresh Kumar 	}
10317813dd6fSViresh Kumar 
10327eba0c76SViresh Kumar 	lazy_link_required_opp_table(opp_table);
10337eba0c76SViresh Kumar 
1034cdd6ed90SViresh Kumar 	return 0;
1035ba003319SViresh Kumar 
103603758d60SViresh Kumar remove_static_opp:
103703758d60SViresh Kumar 	_opp_remove_all_static(opp_table);
1038ba003319SViresh Kumar 
1039ba003319SViresh Kumar 	return ret;
10407813dd6fSViresh Kumar }
10417813dd6fSViresh Kumar 
10427813dd6fSViresh Kumar /* Initializes OPP tables based on old-deprecated bindings */
_of_add_opp_table_v1(struct device * dev,struct opp_table * opp_table)10435ed4cecdSViresh Kumar static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
10447813dd6fSViresh Kumar {
10457813dd6fSViresh Kumar 	const struct property *prop;
10467813dd6fSViresh Kumar 	const __be32 *val;
10477813dd6fSViresh Kumar 	int nr, ret = 0;
10487813dd6fSViresh Kumar 
104990d46d71SViresh Kumar 	mutex_lock(&opp_table->lock);
105090d46d71SViresh Kumar 	if (opp_table->parsed_static_opps) {
105190d46d71SViresh Kumar 		opp_table->parsed_static_opps++;
105290d46d71SViresh Kumar 		mutex_unlock(&opp_table->lock);
105390d46d71SViresh Kumar 		return 0;
105490d46d71SViresh Kumar 	}
105590d46d71SViresh Kumar 
105690d46d71SViresh Kumar 	opp_table->parsed_static_opps = 1;
105790d46d71SViresh Kumar 	mutex_unlock(&opp_table->lock);
105890d46d71SViresh Kumar 
10597813dd6fSViresh Kumar 	prop = of_find_property(dev->of_node, "operating-points", NULL);
106090d46d71SViresh Kumar 	if (!prop) {
106190d46d71SViresh Kumar 		ret = -ENODEV;
106290d46d71SViresh Kumar 		goto remove_static_opp;
106390d46d71SViresh Kumar 	}
106490d46d71SViresh Kumar 	if (!prop->value) {
106590d46d71SViresh Kumar 		ret = -ENODATA;
106690d46d71SViresh Kumar 		goto remove_static_opp;
106790d46d71SViresh Kumar 	}
10687813dd6fSViresh Kumar 
10697813dd6fSViresh Kumar 	/*
10707813dd6fSViresh Kumar 	 * Each OPP is a set of tuples consisting of frequency and
10717813dd6fSViresh Kumar 	 * voltage like <freq-kHz vol-uV>.
10727813dd6fSViresh Kumar 	 */
10737813dd6fSViresh Kumar 	nr = prop->length / sizeof(u32);
10747813dd6fSViresh Kumar 	if (nr % 2) {
10757813dd6fSViresh Kumar 		dev_err(dev, "%s: Invalid OPP table\n", __func__);
107690d46d71SViresh Kumar 		ret = -EINVAL;
107790d46d71SViresh Kumar 		goto remove_static_opp;
10787813dd6fSViresh Kumar 	}
10797813dd6fSViresh Kumar 
10807813dd6fSViresh Kumar 	val = prop->value;
10817813dd6fSViresh Kumar 	while (nr) {
10827813dd6fSViresh Kumar 		unsigned long freq = be32_to_cpup(val++) * 1000;
10837813dd6fSViresh Kumar 		unsigned long volt = be32_to_cpup(val++);
10847813dd6fSViresh Kumar 
10857813dd6fSViresh Kumar 		ret = _opp_add_v1(opp_table, dev, freq, volt, false);
10867813dd6fSViresh Kumar 		if (ret) {
10877813dd6fSViresh Kumar 			dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
10887813dd6fSViresh Kumar 				__func__, freq, ret);
108990d46d71SViresh Kumar 			goto remove_static_opp;
10907813dd6fSViresh Kumar 		}
10917813dd6fSViresh Kumar 		nr -= 2;
10927813dd6fSViresh Kumar 	}
10937813dd6fSViresh Kumar 
10941f6620f8SViresh Kumar 	return 0;
10951f6620f8SViresh Kumar 
109690d46d71SViresh Kumar remove_static_opp:
109790d46d71SViresh Kumar 	_opp_remove_all_static(opp_table);
109890d46d71SViresh Kumar 
10997813dd6fSViresh Kumar 	return ret;
11007813dd6fSViresh Kumar }
11017813dd6fSViresh Kumar 
_of_add_table_indexed(struct device * dev,int index)11021e5fb384SViresh Kumar static int _of_add_table_indexed(struct device *dev, int index)
1103fa9b274fSViresh Kumar {
11045ed4cecdSViresh Kumar 	struct opp_table *opp_table;
11058a352fd8SViresh Kumar 	int ret, count;
1106fa9b274fSViresh Kumar 
11075ed4cecdSViresh Kumar 	if (index) {
11088a352fd8SViresh Kumar 		/*
11098a352fd8SViresh Kumar 		 * If only one phandle is present, then the same OPP table
11108a352fd8SViresh Kumar 		 * applies for all index requests.
11118a352fd8SViresh Kumar 		 */
11128a352fd8SViresh Kumar 		count = of_count_phandle_with_args(dev->of_node,
11138a352fd8SViresh Kumar 						   "operating-points-v2", NULL);
11143e27c79cSViresh Kumar 		if (count == 1)
11155ed4cecdSViresh Kumar 			index = 0;
11168a352fd8SViresh Kumar 	}
1117fa9b274fSViresh Kumar 
11181e5fb384SViresh Kumar 	opp_table = _add_opp_table_indexed(dev, index, true);
1119dd461cd9SStephan Gerhold 	if (IS_ERR(opp_table))
1120dd461cd9SStephan Gerhold 		return PTR_ERR(opp_table);
11215ed4cecdSViresh Kumar 
1122406e4765SViresh Kumar 	/*
1123406e4765SViresh Kumar 	 * OPPs have two version of bindings now. Also try the old (v1)
1124406e4765SViresh Kumar 	 * bindings for backward compatibility with older dtbs.
1125406e4765SViresh Kumar 	 */
1126406e4765SViresh Kumar 	if (opp_table->np)
11275ed4cecdSViresh Kumar 		ret = _of_add_opp_table_v2(dev, opp_table);
1128406e4765SViresh Kumar 	else
1129406e4765SViresh Kumar 		ret = _of_add_opp_table_v1(dev, opp_table);
1130406e4765SViresh Kumar 
11315ed4cecdSViresh Kumar 	if (ret)
11325ed4cecdSViresh Kumar 		dev_pm_opp_put_opp_table(opp_table);
1133fa9b274fSViresh Kumar 
1134fa9b274fSViresh Kumar 	return ret;
1135fa9b274fSViresh Kumar }
1136406e4765SViresh Kumar 
devm_pm_opp_of_table_release(void * data)11373d5cfbb6SYangtao Li static void devm_pm_opp_of_table_release(void *data)
11383d5cfbb6SYangtao Li {
11393d5cfbb6SYangtao Li 	dev_pm_opp_of_remove_table(data);
11403d5cfbb6SYangtao Li }
11413d5cfbb6SYangtao Li 
_devm_of_add_table_indexed(struct device * dev,int index)11421e5fb384SViresh Kumar static int _devm_of_add_table_indexed(struct device *dev, int index)
1143e69709f6SDmitry Osipenko {
1144e69709f6SDmitry Osipenko 	int ret;
1145e69709f6SDmitry Osipenko 
11461e5fb384SViresh Kumar 	ret = _of_add_table_indexed(dev, index);
1147e69709f6SDmitry Osipenko 	if (ret)
1148e69709f6SDmitry Osipenko 		return ret;
1149e69709f6SDmitry Osipenko 
1150e69709f6SDmitry Osipenko 	return devm_add_action_or_reset(dev, devm_pm_opp_of_table_release, dev);
1151e69709f6SDmitry Osipenko }
1152e69709f6SDmitry Osipenko 
11533d5cfbb6SYangtao Li /**
11543d5cfbb6SYangtao Li  * devm_pm_opp_of_add_table() - Initialize opp table from device tree
11553d5cfbb6SYangtao Li  * @dev:	device pointer used to lookup OPP table.
11563d5cfbb6SYangtao Li  *
11573d5cfbb6SYangtao Li  * Register the initial OPP table with the OPP library for given device.
11583d5cfbb6SYangtao Li  *
11593d5cfbb6SYangtao Li  * The opp_table structure will be freed after the device is destroyed.
11603d5cfbb6SYangtao Li  *
11613d5cfbb6SYangtao Li  * Return:
11623d5cfbb6SYangtao Li  * 0		On success OR
11633d5cfbb6SYangtao Li  *		Duplicate OPPs (both freq and volt are same) and opp->available
11643d5cfbb6SYangtao Li  * -EEXIST	Freq are same and volt are different OR
11653d5cfbb6SYangtao Li  *		Duplicate OPPs (both freq and volt are same) and !opp->available
11663d5cfbb6SYangtao Li  * -ENOMEM	Memory allocation failure
11673d5cfbb6SYangtao Li  * -ENODEV	when 'operating-points' property is not found or is invalid data
11683d5cfbb6SYangtao Li  *		in device node.
11693d5cfbb6SYangtao Li  * -ENODATA	when empty 'operating-points' property is found
11703d5cfbb6SYangtao Li  * -EINVAL	when invalid entries are found in opp-v2 table
11713d5cfbb6SYangtao Li  */
devm_pm_opp_of_add_table(struct device * dev)11723d5cfbb6SYangtao Li int devm_pm_opp_of_add_table(struct device *dev)
11733d5cfbb6SYangtao Li {
11741e5fb384SViresh Kumar 	return _devm_of_add_table_indexed(dev, 0);
11753d5cfbb6SYangtao Li }
11763d5cfbb6SYangtao Li EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
11773d5cfbb6SYangtao Li 
1178406e4765SViresh Kumar /**
1179406e4765SViresh Kumar  * dev_pm_opp_of_add_table() - Initialize opp table from device tree
1180406e4765SViresh Kumar  * @dev:	device pointer used to lookup OPP table.
1181406e4765SViresh Kumar  *
1182406e4765SViresh Kumar  * Register the initial OPP table with the OPP library for given device.
1183406e4765SViresh Kumar  *
1184406e4765SViresh Kumar  * Return:
1185406e4765SViresh Kumar  * 0		On success OR
1186406e4765SViresh Kumar  *		Duplicate OPPs (both freq and volt are same) and opp->available
1187406e4765SViresh Kumar  * -EEXIST	Freq are same and volt are different OR
1188406e4765SViresh Kumar  *		Duplicate OPPs (both freq and volt are same) and !opp->available
1189406e4765SViresh Kumar  * -ENOMEM	Memory allocation failure
1190406e4765SViresh Kumar  * -ENODEV	when 'operating-points' property is not found or is invalid data
1191406e4765SViresh Kumar  *		in device node.
1192406e4765SViresh Kumar  * -ENODATA	when empty 'operating-points' property is found
1193406e4765SViresh Kumar  * -EINVAL	when invalid entries are found in opp-v2 table
1194406e4765SViresh Kumar  */
dev_pm_opp_of_add_table(struct device * dev)1195406e4765SViresh Kumar int dev_pm_opp_of_add_table(struct device *dev)
1196406e4765SViresh Kumar {
11971e5fb384SViresh Kumar 	return _of_add_table_indexed(dev, 0);
1198406e4765SViresh Kumar }
1199406e4765SViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
1200406e4765SViresh Kumar 
1201406e4765SViresh Kumar /**
1202406e4765SViresh Kumar  * dev_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree
1203406e4765SViresh Kumar  * @dev:	device pointer used to lookup OPP table.
1204406e4765SViresh Kumar  * @index:	Index number.
1205406e4765SViresh Kumar  *
1206406e4765SViresh Kumar  * Register the initial OPP table with the OPP library for given device only
1207406e4765SViresh Kumar  * using the "operating-points-v2" property.
1208406e4765SViresh Kumar  *
1209406e4765SViresh Kumar  * Return: Refer to dev_pm_opp_of_add_table() for return values.
1210406e4765SViresh Kumar  */
dev_pm_opp_of_add_table_indexed(struct device * dev,int index)1211406e4765SViresh Kumar int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
1212406e4765SViresh Kumar {
12131e5fb384SViresh Kumar 	return _of_add_table_indexed(dev, index);
1214406e4765SViresh Kumar }
1215fa9b274fSViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
1216fa9b274fSViresh Kumar 
1217559fef0dSViresh Kumar /**
1218e69709f6SDmitry Osipenko  * devm_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree
1219e69709f6SDmitry Osipenko  * @dev:	device pointer used to lookup OPP table.
1220e69709f6SDmitry Osipenko  * @index:	Index number.
1221e69709f6SDmitry Osipenko  *
1222e69709f6SDmitry Osipenko  * This is a resource-managed variant of dev_pm_opp_of_add_table_indexed().
1223e69709f6SDmitry Osipenko  */
devm_pm_opp_of_add_table_indexed(struct device * dev,int index)1224e69709f6SDmitry Osipenko int devm_pm_opp_of_add_table_indexed(struct device *dev, int index)
1225e69709f6SDmitry Osipenko {
12261e5fb384SViresh Kumar 	return _devm_of_add_table_indexed(dev, index);
1227e69709f6SDmitry Osipenko }
1228e69709f6SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_indexed);
1229e69709f6SDmitry Osipenko 
12307813dd6fSViresh Kumar /* CPU device specific helpers */
12317813dd6fSViresh Kumar 
12327813dd6fSViresh Kumar /**
12337813dd6fSViresh Kumar  * dev_pm_opp_of_cpumask_remove_table() - Removes OPP table for @cpumask
12347813dd6fSViresh Kumar  * @cpumask:	cpumask for which OPP table needs to be removed
12357813dd6fSViresh Kumar  *
12367813dd6fSViresh Kumar  * This removes the OPP tables for CPUs present in the @cpumask.
12377813dd6fSViresh Kumar  * This should be used only to remove static entries created from DT.
12387813dd6fSViresh Kumar  */
dev_pm_opp_of_cpumask_remove_table(const struct cpumask * cpumask)12397813dd6fSViresh Kumar void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
12407813dd6fSViresh Kumar {
12412a4eb735SViresh Kumar 	_dev_pm_opp_cpumask_remove_table(cpumask, -1);
12427813dd6fSViresh Kumar }
12437813dd6fSViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
12447813dd6fSViresh Kumar 
12457813dd6fSViresh Kumar /**
12467813dd6fSViresh Kumar  * dev_pm_opp_of_cpumask_add_table() - Adds OPP table for @cpumask
12477813dd6fSViresh Kumar  * @cpumask:	cpumask for which OPP table needs to be added.
12487813dd6fSViresh Kumar  *
12497813dd6fSViresh Kumar  * This adds the OPP tables for CPUs present in the @cpumask.
12507813dd6fSViresh Kumar  */
dev_pm_opp_of_cpumask_add_table(const struct cpumask * cpumask)12517813dd6fSViresh Kumar int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
12527813dd6fSViresh Kumar {
12537813dd6fSViresh Kumar 	struct device *cpu_dev;
125450b6b87cSViresh Kumar 	int cpu, ret;
12557813dd6fSViresh Kumar 
125650b6b87cSViresh Kumar 	if (WARN_ON(cpumask_empty(cpumask)))
125750b6b87cSViresh Kumar 		return -ENODEV;
12587813dd6fSViresh Kumar 
12597813dd6fSViresh Kumar 	for_each_cpu(cpu, cpumask) {
12607813dd6fSViresh Kumar 		cpu_dev = get_cpu_device(cpu);
12617813dd6fSViresh Kumar 		if (!cpu_dev) {
12627813dd6fSViresh Kumar 			pr_err("%s: failed to get cpu%d device\n", __func__,
12637813dd6fSViresh Kumar 			       cpu);
126450b6b87cSViresh Kumar 			ret = -ENODEV;
126550b6b87cSViresh Kumar 			goto remove_table;
12667813dd6fSViresh Kumar 		}
12677813dd6fSViresh Kumar 
12687813dd6fSViresh Kumar 		ret = dev_pm_opp_of_add_table(cpu_dev);
12697813dd6fSViresh Kumar 		if (ret) {
12707813dd6fSViresh Kumar 			/*
12717813dd6fSViresh Kumar 			 * OPP may get registered dynamically, don't print error
12727813dd6fSViresh Kumar 			 * message here.
12737813dd6fSViresh Kumar 			 */
12747813dd6fSViresh Kumar 			pr_debug("%s: couldn't find opp table for cpu:%d, %d\n",
12757813dd6fSViresh Kumar 				 __func__, cpu, ret);
12767813dd6fSViresh Kumar 
127750b6b87cSViresh Kumar 			goto remove_table;
127850b6b87cSViresh Kumar 		}
127950b6b87cSViresh Kumar 	}
128050b6b87cSViresh Kumar 
128150b6b87cSViresh Kumar 	return 0;
128250b6b87cSViresh Kumar 
128350b6b87cSViresh Kumar remove_table:
12847813dd6fSViresh Kumar 	/* Free all other OPPs */
12852a4eb735SViresh Kumar 	_dev_pm_opp_cpumask_remove_table(cpumask, cpu);
12867813dd6fSViresh Kumar 
12877813dd6fSViresh Kumar 	return ret;
12887813dd6fSViresh Kumar }
12897813dd6fSViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
12907813dd6fSViresh Kumar 
12917813dd6fSViresh Kumar /*
12927813dd6fSViresh Kumar  * Works only for OPP v2 bindings.
12937813dd6fSViresh Kumar  *
12947813dd6fSViresh Kumar  * Returns -ENOENT if operating-points-v2 bindings aren't supported.
12957813dd6fSViresh Kumar  */
12967813dd6fSViresh Kumar /**
12977813dd6fSViresh Kumar  * dev_pm_opp_of_get_sharing_cpus() - Get cpumask of CPUs sharing OPPs with
12987813dd6fSViresh Kumar  *				      @cpu_dev using operating-points-v2
12997813dd6fSViresh Kumar  *				      bindings.
13007813dd6fSViresh Kumar  *
13017813dd6fSViresh Kumar  * @cpu_dev:	CPU device for which we do this operation
13027813dd6fSViresh Kumar  * @cpumask:	cpumask to update with information of sharing CPUs
13037813dd6fSViresh Kumar  *
13047813dd6fSViresh Kumar  * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
13057813dd6fSViresh Kumar  *
13067813dd6fSViresh Kumar  * Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev.
13077813dd6fSViresh Kumar  */
dev_pm_opp_of_get_sharing_cpus(struct device * cpu_dev,struct cpumask * cpumask)13087813dd6fSViresh Kumar int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
13097813dd6fSViresh Kumar 				   struct cpumask *cpumask)
13107813dd6fSViresh Kumar {
13117813dd6fSViresh Kumar 	struct device_node *np, *tmp_np, *cpu_np;
13127813dd6fSViresh Kumar 	int cpu, ret = 0;
13137813dd6fSViresh Kumar 
13147813dd6fSViresh Kumar 	/* Get OPP descriptor node */
13157813dd6fSViresh Kumar 	np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
13167813dd6fSViresh Kumar 	if (!np) {
13177813dd6fSViresh Kumar 		dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__);
13187813dd6fSViresh Kumar 		return -ENOENT;
13197813dd6fSViresh Kumar 	}
13207813dd6fSViresh Kumar 
13217813dd6fSViresh Kumar 	cpumask_set_cpu(cpu_dev->id, cpumask);
13227813dd6fSViresh Kumar 
13237813dd6fSViresh Kumar 	/* OPPs are shared ? */
13247813dd6fSViresh Kumar 	if (!of_property_read_bool(np, "opp-shared"))
13257813dd6fSViresh Kumar 		goto put_cpu_node;
13267813dd6fSViresh Kumar 
13277813dd6fSViresh Kumar 	for_each_possible_cpu(cpu) {
13287813dd6fSViresh Kumar 		if (cpu == cpu_dev->id)
13297813dd6fSViresh Kumar 			continue;
13307813dd6fSViresh Kumar 
13319867999fSSudeep Holla 		cpu_np = of_cpu_device_node_get(cpu);
13327813dd6fSViresh Kumar 		if (!cpu_np) {
13337813dd6fSViresh Kumar 			dev_err(cpu_dev, "%s: failed to get cpu%d node\n",
13347813dd6fSViresh Kumar 				__func__, cpu);
13357813dd6fSViresh Kumar 			ret = -ENOENT;
13367813dd6fSViresh Kumar 			goto put_cpu_node;
13377813dd6fSViresh Kumar 		}
13387813dd6fSViresh Kumar 
13397813dd6fSViresh Kumar 		/* Get OPP descriptor node */
1340fa9b274fSViresh Kumar 		tmp_np = _opp_of_get_opp_desc_node(cpu_np, 0);
13419867999fSSudeep Holla 		of_node_put(cpu_np);
13427813dd6fSViresh Kumar 		if (!tmp_np) {
13437813dd6fSViresh Kumar 			pr_err("%pOF: Couldn't find opp node\n", cpu_np);
13447813dd6fSViresh Kumar 			ret = -ENOENT;
13457813dd6fSViresh Kumar 			goto put_cpu_node;
13467813dd6fSViresh Kumar 		}
13477813dd6fSViresh Kumar 
13487813dd6fSViresh Kumar 		/* CPUs are sharing opp node */
13497813dd6fSViresh Kumar 		if (np == tmp_np)
13507813dd6fSViresh Kumar 			cpumask_set_cpu(cpu, cpumask);
13517813dd6fSViresh Kumar 
13527813dd6fSViresh Kumar 		of_node_put(tmp_np);
13537813dd6fSViresh Kumar 	}
13547813dd6fSViresh Kumar 
13557813dd6fSViresh Kumar put_cpu_node:
13567813dd6fSViresh Kumar 	of_node_put(np);
13577813dd6fSViresh Kumar 	return ret;
13587813dd6fSViresh Kumar }
13597813dd6fSViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus);
1360a88bd2a5SViresh Kumar 
1361a88bd2a5SViresh Kumar /**
13624c6a343eSViresh Kumar  * of_get_required_opp_performance_state() - Search for required OPP and return its performance state.
1363a88bd2a5SViresh Kumar  * @np: Node that contains the "required-opps" property.
13644c6a343eSViresh Kumar  * @index: Index of the phandle to parse.
1365a88bd2a5SViresh Kumar  *
13664c6a343eSViresh Kumar  * Returns the performance state of the OPP pointed out by the "required-opps"
13674c6a343eSViresh Kumar  * property at @index in @np.
1368a88bd2a5SViresh Kumar  *
13692feb5a89SViresh Kumar  * Return: Zero or positive performance state on success, otherwise negative
13702feb5a89SViresh Kumar  * value on errors.
1371a88bd2a5SViresh Kumar  */
of_get_required_opp_performance_state(struct device_node * np,int index)13722feb5a89SViresh Kumar int of_get_required_opp_performance_state(struct device_node *np, int index)
1373a88bd2a5SViresh Kumar {
13744c6a343eSViresh Kumar 	struct dev_pm_opp *opp;
1375a88bd2a5SViresh Kumar 	struct device_node *required_np;
1376a88bd2a5SViresh Kumar 	struct opp_table *opp_table;
13772feb5a89SViresh Kumar 	int pstate = -EINVAL;
1378a88bd2a5SViresh Kumar 
13794c6a343eSViresh Kumar 	required_np = of_parse_required_opp(np, index);
13804c6a343eSViresh Kumar 	if (!required_np)
1381020d86fcSRajendra Nayak 		return -ENODEV;
1382a88bd2a5SViresh Kumar 
13834c6a343eSViresh Kumar 	opp_table = _find_table_of_opp_np(required_np);
13844c6a343eSViresh Kumar 	if (IS_ERR(opp_table)) {
13854c6a343eSViresh Kumar 		pr_err("%s: Failed to find required OPP table %pOF: %ld\n",
13864c6a343eSViresh Kumar 		       __func__, np, PTR_ERR(opp_table));
13874c6a343eSViresh Kumar 		goto put_required_np;
1388a88bd2a5SViresh Kumar 	}
1389a88bd2a5SViresh Kumar 
139084cb7ff3SViresh Kumar 	/* The OPP tables must belong to a genpd */
139184cb7ff3SViresh Kumar 	if (unlikely(!opp_table->is_genpd)) {
139284cb7ff3SViresh Kumar 		pr_err("%s: Performance state is only valid for genpds.\n", __func__);
139384cb7ff3SViresh Kumar 		goto put_required_np;
139484cb7ff3SViresh Kumar 	}
139584cb7ff3SViresh Kumar 
13964c6a343eSViresh Kumar 	opp = _find_opp_of_np(opp_table, required_np);
13974c6a343eSViresh Kumar 	if (opp) {
13987c41cdcdSViresh Kumar 		pstate = opp->level;
13994c6a343eSViresh Kumar 		dev_pm_opp_put(opp);
1400a88bd2a5SViresh Kumar 	}
1401a88bd2a5SViresh Kumar 
1402a88bd2a5SViresh Kumar 	dev_pm_opp_put_opp_table(opp_table);
1403a88bd2a5SViresh Kumar 
14044c6a343eSViresh Kumar put_required_np:
14054c6a343eSViresh Kumar 	of_node_put(required_np);
14064c6a343eSViresh Kumar 
14074c6a343eSViresh Kumar 	return pstate;
1408a88bd2a5SViresh Kumar }
14094c6a343eSViresh Kumar EXPORT_SYMBOL_GPL(of_get_required_opp_performance_state);
1410e2f4b5f8SViresh Kumar 
1411e2f4b5f8SViresh Kumar /**
1412e2f4b5f8SViresh Kumar  * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp
1413e2f4b5f8SViresh Kumar  * @opp:	opp for which DT node has to be returned for
1414e2f4b5f8SViresh Kumar  *
1415e2f4b5f8SViresh Kumar  * Return: DT node corresponding to the opp, else 0 on success.
1416e2f4b5f8SViresh Kumar  *
1417e2f4b5f8SViresh Kumar  * The caller needs to put the node with of_node_put() after using it.
1418e2f4b5f8SViresh Kumar  */
dev_pm_opp_get_of_node(struct dev_pm_opp * opp)1419e2f4b5f8SViresh Kumar struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
1420e2f4b5f8SViresh Kumar {
1421e2f4b5f8SViresh Kumar 	if (IS_ERR_OR_NULL(opp)) {
1422e2f4b5f8SViresh Kumar 		pr_err("%s: Invalid parameters\n", __func__);
1423e2f4b5f8SViresh Kumar 		return NULL;
1424e2f4b5f8SViresh Kumar 	}
1425e2f4b5f8SViresh Kumar 
1426e2f4b5f8SViresh Kumar 	return of_node_get(opp->np);
1427e2f4b5f8SViresh Kumar }
1428e2f4b5f8SViresh Kumar EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
1429a4f342b9SQuentin Perret 
1430a4f342b9SQuentin Perret /*
1431a4f342b9SQuentin Perret  * Callback function provided to the Energy Model framework upon registration.
143232bf8bc9SLukasz Luba  * It provides the power used by @dev at @kHz if it is the frequency of an
143332bf8bc9SLukasz Luba  * existing OPP, or at the frequency of the first OPP above @kHz otherwise
143432bf8bc9SLukasz Luba  * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
1435ae6ccaa6SLukasz Luba  * frequency and @uW to the associated power.
143632bf8bc9SLukasz Luba  *
143732bf8bc9SLukasz Luba  * Returns 0 on success or a proper -EINVAL value in case of error.
143832bf8bc9SLukasz Luba  */
143932bf8bc9SLukasz Luba static int __maybe_unused
_get_dt_power(struct device * dev,unsigned long * uW,unsigned long * kHz)1440ae6ccaa6SLukasz Luba _get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz)
144132bf8bc9SLukasz Luba {
144232bf8bc9SLukasz Luba 	struct dev_pm_opp *opp;
144332bf8bc9SLukasz Luba 	unsigned long opp_freq, opp_power;
144432bf8bc9SLukasz Luba 
144532bf8bc9SLukasz Luba 	/* Find the right frequency and related OPP */
144632bf8bc9SLukasz Luba 	opp_freq = *kHz * 1000;
144732bf8bc9SLukasz Luba 	opp = dev_pm_opp_find_freq_ceil(dev, &opp_freq);
144832bf8bc9SLukasz Luba 	if (IS_ERR(opp))
144932bf8bc9SLukasz Luba 		return -EINVAL;
145032bf8bc9SLukasz Luba 
145132bf8bc9SLukasz Luba 	opp_power = dev_pm_opp_get_power(opp);
145232bf8bc9SLukasz Luba 	dev_pm_opp_put(opp);
145332bf8bc9SLukasz Luba 	if (!opp_power)
145432bf8bc9SLukasz Luba 		return -EINVAL;
145532bf8bc9SLukasz Luba 
145632bf8bc9SLukasz Luba 	*kHz = opp_freq / 1000;
1457ae6ccaa6SLukasz Luba 	*uW = opp_power;
145832bf8bc9SLukasz Luba 
145932bf8bc9SLukasz Luba 	return 0;
146032bf8bc9SLukasz Luba }
146132bf8bc9SLukasz Luba 
146232bf8bc9SLukasz Luba /*
146332bf8bc9SLukasz Luba  * Callback function provided to the Energy Model framework upon registration.
14640e0ffa85SLukasz Luba  * This computes the power estimated by @dev at @kHz if it is the frequency
1465a4f342b9SQuentin Perret  * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
1466a4f342b9SQuentin Perret  * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
1467ae6ccaa6SLukasz Luba  * frequency and @uW to the associated power. The power is estimated as
14680e0ffa85SLukasz Luba  * P = C * V^2 * f with C being the device's capacitance and V and f
14690e0ffa85SLukasz Luba  * respectively the voltage and frequency of the OPP.
1470a4f342b9SQuentin Perret  *
14710e0ffa85SLukasz Luba  * Returns -EINVAL if the power calculation failed because of missing
14720e0ffa85SLukasz Luba  * parameters, 0 otherwise.
1473a4f342b9SQuentin Perret  */
_get_power(struct device * dev,unsigned long * uW,unsigned long * kHz)1474ae6ccaa6SLukasz Luba static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
147575a3a99aSLukasz Luba 				     unsigned long *kHz)
1476a4f342b9SQuentin Perret {
1477a4f342b9SQuentin Perret 	struct dev_pm_opp *opp;
1478a4f342b9SQuentin Perret 	struct device_node *np;
1479a4f342b9SQuentin Perret 	unsigned long mV, Hz;
1480a4f342b9SQuentin Perret 	u32 cap;
1481a4f342b9SQuentin Perret 	u64 tmp;
1482a4f342b9SQuentin Perret 	int ret;
1483a4f342b9SQuentin Perret 
14840e0ffa85SLukasz Luba 	np = of_node_get(dev->of_node);
1485a4f342b9SQuentin Perret 	if (!np)
1486a4f342b9SQuentin Perret 		return -EINVAL;
1487a4f342b9SQuentin Perret 
1488a4f342b9SQuentin Perret 	ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
1489a4f342b9SQuentin Perret 	of_node_put(np);
1490a4f342b9SQuentin Perret 	if (ret)
1491a4f342b9SQuentin Perret 		return -EINVAL;
1492a4f342b9SQuentin Perret 
1493a4f342b9SQuentin Perret 	Hz = *kHz * 1000;
14940e0ffa85SLukasz Luba 	opp = dev_pm_opp_find_freq_ceil(dev, &Hz);
1495a4f342b9SQuentin Perret 	if (IS_ERR(opp))
1496a4f342b9SQuentin Perret 		return -EINVAL;
1497a4f342b9SQuentin Perret 
1498a4f342b9SQuentin Perret 	mV = dev_pm_opp_get_voltage(opp) / 1000;
1499a4f342b9SQuentin Perret 	dev_pm_opp_put(opp);
1500a4f342b9SQuentin Perret 	if (!mV)
1501a4f342b9SQuentin Perret 		return -EINVAL;
1502a4f342b9SQuentin Perret 
1503a4f342b9SQuentin Perret 	tmp = (u64)cap * mV * mV * (Hz / 1000000);
1504ae6ccaa6SLukasz Luba 	/* Provide power in micro-Watts */
1505ae6ccaa6SLukasz Luba 	do_div(tmp, 1000000);
1506a4f342b9SQuentin Perret 
1507ae6ccaa6SLukasz Luba 	*uW = (unsigned long)tmp;
1508a4f342b9SQuentin Perret 	*kHz = Hz / 1000;
1509a4f342b9SQuentin Perret 
1510a4f342b9SQuentin Perret 	return 0;
1511a4f342b9SQuentin Perret }
1512a4f342b9SQuentin Perret 
_of_has_opp_microwatt_property(struct device * dev)151332bf8bc9SLukasz Luba static bool _of_has_opp_microwatt_property(struct device *dev)
151432bf8bc9SLukasz Luba {
151532bf8bc9SLukasz Luba 	unsigned long power, freq = 0;
151632bf8bc9SLukasz Luba 	struct dev_pm_opp *opp;
151732bf8bc9SLukasz Luba 
151832bf8bc9SLukasz Luba 	/* Check if at least one OPP has needed property */
151932bf8bc9SLukasz Luba 	opp = dev_pm_opp_find_freq_ceil(dev, &freq);
152032bf8bc9SLukasz Luba 	if (IS_ERR(opp))
152132bf8bc9SLukasz Luba 		return false;
152232bf8bc9SLukasz Luba 
152332bf8bc9SLukasz Luba 	power = dev_pm_opp_get_power(opp);
152432bf8bc9SLukasz Luba 	dev_pm_opp_put(opp);
152532bf8bc9SLukasz Luba 	if (!power)
152632bf8bc9SLukasz Luba 		return false;
152732bf8bc9SLukasz Luba 
152832bf8bc9SLukasz Luba 	return true;
152932bf8bc9SLukasz Luba }
153032bf8bc9SLukasz Luba 
1531a4f342b9SQuentin Perret /**
1532a4f342b9SQuentin Perret  * dev_pm_opp_of_register_em() - Attempt to register an Energy Model
15330e0ffa85SLukasz Luba  * @dev		: Device for which an Energy Model has to be registered
15340e0ffa85SLukasz Luba  * @cpus	: CPUs for which an Energy Model has to be registered. For
15350e0ffa85SLukasz Luba  *		other type of devices it should be set to NULL.
1536a4f342b9SQuentin Perret  *
1537a4f342b9SQuentin Perret  * This checks whether the "dynamic-power-coefficient" devicetree property has
1538a4f342b9SQuentin Perret  * been specified, and tries to register an Energy Model with it if it has.
15390e0ffa85SLukasz Luba  * Having this property means the voltages are known for OPPs and the EM
15400e0ffa85SLukasz Luba  * might be calculated.
1541a4f342b9SQuentin Perret  */
dev_pm_opp_of_register_em(struct device * dev,struct cpumask * cpus)15420e0ffa85SLukasz Luba int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
1543a4f342b9SQuentin Perret {
154432bf8bc9SLukasz Luba 	struct em_data_callback em_cb;
1545a4f342b9SQuentin Perret 	struct device_node *np;
15460e0ffa85SLukasz Luba 	int ret, nr_opp;
1547a4f342b9SQuentin Perret 	u32 cap;
1548a4f342b9SQuentin Perret 
15490e0ffa85SLukasz Luba 	if (IS_ERR_OR_NULL(dev)) {
15500e0ffa85SLukasz Luba 		ret = -EINVAL;
15510e0ffa85SLukasz Luba 		goto failed;
15520e0ffa85SLukasz Luba 	}
1553a4f342b9SQuentin Perret 
15540e0ffa85SLukasz Luba 	nr_opp = dev_pm_opp_get_opp_count(dev);
15550e0ffa85SLukasz Luba 	if (nr_opp <= 0) {
15560e0ffa85SLukasz Luba 		ret = -EINVAL;
15570e0ffa85SLukasz Luba 		goto failed;
15580e0ffa85SLukasz Luba 	}
1559a4f342b9SQuentin Perret 
156032bf8bc9SLukasz Luba 	/* First, try to find more precised Energy Model in DT */
156132bf8bc9SLukasz Luba 	if (_of_has_opp_microwatt_property(dev)) {
156232bf8bc9SLukasz Luba 		EM_SET_ACTIVE_POWER_CB(em_cb, _get_dt_power);
156332bf8bc9SLukasz Luba 		goto register_em;
156432bf8bc9SLukasz Luba 	}
156532bf8bc9SLukasz Luba 
15660e0ffa85SLukasz Luba 	np = of_node_get(dev->of_node);
15670e0ffa85SLukasz Luba 	if (!np) {
15680e0ffa85SLukasz Luba 		ret = -EINVAL;
15690e0ffa85SLukasz Luba 		goto failed;
15700e0ffa85SLukasz Luba 	}
1571a4f342b9SQuentin Perret 
1572a4f342b9SQuentin Perret 	/*
1573a4f342b9SQuentin Perret 	 * Register an EM only if the 'dynamic-power-coefficient' property is
1574a4f342b9SQuentin Perret 	 * set in devicetree. It is assumed the voltage values are known if that
1575a4f342b9SQuentin Perret 	 * property is set since it is useless otherwise. If voltages are not
1576a4f342b9SQuentin Perret 	 * known, just let the EM registration fail with an error to alert the
1577a4f342b9SQuentin Perret 	 * user about the inconsistent configuration.
1578a4f342b9SQuentin Perret 	 */
1579a4f342b9SQuentin Perret 	ret = of_property_read_u32(np, "dynamic-power-coefficient", &cap);
1580a4f342b9SQuentin Perret 	of_node_put(np);
15810e0ffa85SLukasz Luba 	if (ret || !cap) {
15820e0ffa85SLukasz Luba 		dev_dbg(dev, "Couldn't find proper 'dynamic-power-coefficient' in DT\n");
15830e0ffa85SLukasz Luba 		ret = -EINVAL;
15840e0ffa85SLukasz Luba 		goto failed;
15850e0ffa85SLukasz Luba 	}
1586a4f342b9SQuentin Perret 
158732bf8bc9SLukasz Luba 	EM_SET_ACTIVE_POWER_CB(em_cb, _get_power);
158832bf8bc9SLukasz Luba 
158932bf8bc9SLukasz Luba register_em:
1590c250d50fSLukasz Luba 	ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus, true);
15910e0ffa85SLukasz Luba 	if (ret)
15920e0ffa85SLukasz Luba 		goto failed;
15930e0ffa85SLukasz Luba 
15940e0ffa85SLukasz Luba 	return 0;
15950e0ffa85SLukasz Luba 
15960e0ffa85SLukasz Luba failed:
15970e0ffa85SLukasz Luba 	dev_dbg(dev, "Couldn't register Energy Model %d\n", ret);
15980e0ffa85SLukasz Luba 	return ret;
1599a4f342b9SQuentin Perret }
1600a4f342b9SQuentin Perret EXPORT_SYMBOL_GPL(dev_pm_opp_of_register_em);
1601