Skip to content

Commit 32bf8bc

Browse files
lukaszluba-armvireshk
authored andcommitted
OPP: Add support of "opp-microwatt" for EM registration
The Energy Model (EM) can be created based on DT entry: 'dynamic-power-coefficient'. It's a 'simple' EM which is limited to the dynamic power. It has to fit into the math formula which requires also information about voltage. Some of the platforms don't expose voltage information, thus it's not possible to use EM registration using DT. This patch aims to fix it. It introduces new implementation of the EM registration callback. The new mechanism relies on the new OPP feature allowing to get power (which is coming from "opp-microwatt" DT property) expressed in micro-Watts. The patch also opens new opportunity to better support platforms, which have a decent static power. It allows to register the EM based on real power measurements which models total power (static + dynamic), so better reflects real HW. Signed-off-by: Lukasz Luba <lukasz.luba@arm.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
1 parent caeea9e commit 32bf8bc

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

drivers/opp/of.c

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,38 @@ struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
14381438
}
14391439
EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
14401440

1441+
/*
1442+
* Callback function provided to the Energy Model framework upon registration.
1443+
* It provides the power used by @dev at @kHz if it is the frequency of an
1444+
* existing OPP, or at the frequency of the first OPP above @kHz otherwise
1445+
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
1446+
* frequency and @mW to the associated power.
1447+
*
1448+
* Returns 0 on success or a proper -EINVAL value in case of error.
1449+
*/
1450+
static int __maybe_unused
1451+
_get_dt_power(unsigned long *mW, unsigned long *kHz, struct device *dev)
1452+
{
1453+
struct dev_pm_opp *opp;
1454+
unsigned long opp_freq, opp_power;
1455+
1456+
/* Find the right frequency and related OPP */
1457+
opp_freq = *kHz * 1000;
1458+
opp = dev_pm_opp_find_freq_ceil(dev, &opp_freq);
1459+
if (IS_ERR(opp))
1460+
return -EINVAL;
1461+
1462+
opp_power = dev_pm_opp_get_power(opp);
1463+
dev_pm_opp_put(opp);
1464+
if (!opp_power)
1465+
return -EINVAL;
1466+
1467+
*kHz = opp_freq / 1000;
1468+
*mW = opp_power / 1000;
1469+
1470+
return 0;
1471+
}
1472+
14411473
/*
14421474
* Callback function provided to the Energy Model framework upon registration.
14431475
* This computes the power estimated by @dev at @kHz if it is the frequency
@@ -1488,6 +1520,24 @@ static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
14881520
return 0;
14891521
}
14901522

1523+
static bool _of_has_opp_microwatt_property(struct device *dev)
1524+
{
1525+
unsigned long power, freq = 0;
1526+
struct dev_pm_opp *opp;
1527+
1528+
/* Check if at least one OPP has needed property */
1529+
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
1530+
if (IS_ERR(opp))
1531+
return false;
1532+
1533+
power = dev_pm_opp_get_power(opp);
1534+
dev_pm_opp_put(opp);
1535+
if (!power)
1536+
return false;
1537+
1538+
return true;
1539+
}
1540+
14911541
/**
14921542
* dev_pm_opp_of_register_em() - Attempt to register an Energy Model
14931543
* @dev : Device for which an Energy Model has to be registered
@@ -1501,7 +1551,7 @@ static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
15011551
*/
15021552
int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
15031553
{
1504-
struct em_data_callback em_cb = EM_DATA_CB(_get_power);
1554+
struct em_data_callback em_cb;
15051555
struct device_node *np;
15061556
int ret, nr_opp;
15071557
u32 cap;
@@ -1517,6 +1567,12 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
15171567
goto failed;
15181568
}
15191569

1570+
/* First, try to find more precised Energy Model in DT */
1571+
if (_of_has_opp_microwatt_property(dev)) {
1572+
EM_SET_ACTIVE_POWER_CB(em_cb, _get_dt_power);
1573+
goto register_em;
1574+
}
1575+
15201576
np = of_node_get(dev->of_node);
15211577
if (!np) {
15221578
ret = -EINVAL;
@@ -1538,6 +1594,9 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
15381594
goto failed;
15391595
}
15401596

1597+
EM_SET_ACTIVE_POWER_CB(em_cb, _get_power);
1598+
1599+
register_em:
15411600
ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus, true);
15421601
if (ret)
15431602
goto failed;

0 commit comments

Comments
 (0)