- Use local_clock() instead of jiffies in the cpufreq statistics to
improve accuracy (Viresh Kumar).
- Fix up OPP usage in the cpufreq-dt and qcom-cpufreq-nvmem cpufreq
drivers (Viresh Kumar).
- Clean up the cpufreq core, the intel_pstate driver and the
schedutil cpufreq governor (Rafael Wysocki).
- Fix up error code paths in the sti-cpufreq and mediatek cpufreq
drivers (Yangtao Li, Qinglang Miao).
- Fix cpufreq_online() to return error codes instead of success (0)
in all cases when it fails (Wang ShaoBo).
- Add mt8167 support to the mediatek cpufreq driver and blacklist
mt8516 in the cpufreq-dt-platdev driver (Fabien Parent).
- Modify the tegra194 cpufreq driver to always return values from
the frequency table as the current frequency and clean up that
driver (Sumit Gupta, Jon Hunter).
- Modify the arm_scmi cpufreq driver to allow it to discover the
power scale present in the performance protocol and provide this
information to the Energy Model (Lukasz Luba).
- Add missing MODULE_DEVICE_TABLE to several cpufreq drivers (Pali
Rohár).
- Clean up the CPPC cpufreq driver (Ionela Voinescu).
- Fix NVMEM_IMX_OCOTP dependency in the imx cpufreq driver (Arnd
Bergmann).
- Rework the poling interval selection for the polling state in
cpuidle (Mel Gorman).
- Enable suspend-to-idle for PSCI OSI mode in the PSCI cpuidle
driver (Ulf Hansson).
- Modify the OPP framework to support empty (node-less) OPP tables
in DT for passing dependency information (Nicola Mazzucato).
- Fix potential lockdep issue in the OPP core and clean up the OPP
core (Viresh Kumar).
- Modify dev_pm_opp_put_regulators() to accept a NULL argument and
update its users accordingly (Viresh Kumar).
- Add frequency changes tracepoint to devfreq (Matthias Kaehlcke).
- Add support for governor feature flags to devfreq, make devfreq
sysfs file permissions depend on the governor and clean up the
devfreq core (Chanwoo Choi).
- Clean up the tegra20 devfreq driver and deprecate it to allow
another driver based on EMC_STAT to be used instead of it (Dmitry
Osipenko).
- Add interconnect support to the tegra30 devfreq driver, allow it
to take the interconnect and OPP information from DT and clean it
up ((Dmitry Osipenko).
- Add interconnect support to the exynos-bus devfreq driver along
with interconnect properties documentation (Sylwester Nawrocki).
- Add suport for AMD Fam17h and Fam19h processors to the RAPL power
capping driver (Victor Ding, Kim Phillips).
- Fix handling of overly long constraint names in the powercap
framework (Lukasz Luba).
- Fix the wakeup configuration handling for bridges in the ACPI
device power management core (Rafael Wysocki).
- Add support for using an abstract scale for power units in the
Energy Model (EM) and document it (Lukasz Luba).
- Add em_cpu_energy() micro-optimization to the EM (Pavankumar
Kondeti).
- Modify the generic power domains (genpd) framwework to support
suspend-to-idle (Ulf Hansson).
- Fix creation of debugfs nodes in genpd (Thierry Strudel).
- Clean up genpd (Lina Iyer).
- Clean up the core system-wide suspend code and make it print
driver flags for devices with debug enabled (Alex Shi, Patrice
Chotard, Chen Yu).
- Modify the ACPI system reboot code to make it prepare for system
power off to avoid confusing the platform firmware (Kai-Heng Feng).
- Update the pm-graph (multiple changes, mostly usability-related)
and cpupower (online and offline CPU information support) PM
utilities (Todd Brandt, Brahadambal Srinivasan).
-----BEGIN PGP SIGNATURE-----
iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAl/Y8mcSHHJqd0Byand5
c29ja2kubmV0AAoJEILEb/54YlRxjY4QAKsNFJeEtjGCxq7MxQIML3QLAsdJM9of
9kkY9skMEw4v1TRmyy7sW9jZW2pLSRcLJwWRKWu4143qUS3YUp2DQ0lqX4WyXoWu
BhnkhkMUl6iCeBO8CWnt8zsTuqSa20A13sL9LyqN1+7OZKHD8StbT4hKjBncdNNN
4aDj+1uAPyOgj2iCUZuHQ8DtpBvOLjgTh367vbhbufjeJ//8/9+R7s4Xzrj7wtmv
JlE0LDgvge9QeGTpjhxQJzn0q2/H5fg9jbmjPXUfbHJNuyKhrqnmjGyrN5m256JI
8DqGqQtJpmFp7Ihrur3uKTk3gWO05YwJ1FdeEooAKEjEMObm5xuYhKVRoDhmlJAu
G6ui+OAUvNR0FffJtbzvWe/pLovLGOEOHdvTrZxUF8Abo6br3untTm8rKTi1fhaF
wWndSMw0apGsPzCx5T+bE7AbJz2QHFpLhaVAutenuCzNI8xoMlxNKEzsaVz/+FqL
Pq/PdFaM4vNlMbv7hkb/fujkCs/v3EcX2ihzvt7I2o8dBS0D1X8A4mnuWJmiGslw
1ftbJ6M9XacwkPBTHPgeXxJh2C1yxxe5VQ9Z5fWWi7sPOUeJnUwxKaluv+coFndQ
sO6JxsPQ4hQihg8yOxLEkL6Wn68sZlmp+u2Oj+TPFAsAGANIA8rJlBPo1ppJWvdQ
j1OCIc/qzwpH
=BVdX
-----END PGP SIGNATURE-----
Merge tag 'pm-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki:
"These update cpufreq (core and drivers), cpuidle (polling state
implementation and the PSCI driver), the OPP (operating performance
points) framework, devfreq (core and drivers), the power capping RAPL
(Running Average Power Limit) driver, the Energy Model support, the
generic power domains (genpd) framework, the ACPI device power
management, the core system-wide suspend code and power management
utilities.
Specifics:
- Use local_clock() instead of jiffies in the cpufreq statistics to
improve accuracy (Viresh Kumar).
- Fix up OPP usage in the cpufreq-dt and qcom-cpufreq-nvmem cpufreq
drivers (Viresh Kumar).
- Clean up the cpufreq core, the intel_pstate driver and the
schedutil cpufreq governor (Rafael Wysocki).
- Fix up error code paths in the sti-cpufreq and mediatek cpufreq
drivers (Yangtao Li, Qinglang Miao).
- Fix cpufreq_online() to return error codes instead of success (0)
in all cases when it fails (Wang ShaoBo).
- Add mt8167 support to the mediatek cpufreq driver and blacklist
mt8516 in the cpufreq-dt-platdev driver (Fabien Parent).
- Modify the tegra194 cpufreq driver to always return values from the
frequency table as the current frequency and clean up that driver
(Sumit Gupta, Jon Hunter).
- Modify the arm_scmi cpufreq driver to allow it to discover the
power scale present in the performance protocol and provide this
information to the Energy Model (Lukasz Luba).
- Add missing MODULE_DEVICE_TABLE to several cpufreq drivers (Pali
Rohár).
- Clean up the CPPC cpufreq driver (Ionela Voinescu).
- Fix NVMEM_IMX_OCOTP dependency in the imx cpufreq driver (Arnd
Bergmann).
- Rework the poling interval selection for the polling state in
cpuidle (Mel Gorman).
- Enable suspend-to-idle for PSCI OSI mode in the PSCI cpuidle driver
(Ulf Hansson).
- Modify the OPP framework to support empty (node-less) OPP tables in
DT for passing dependency information (Nicola Mazzucato).
- Fix potential lockdep issue in the OPP core and clean up the OPP
core (Viresh Kumar).
- Modify dev_pm_opp_put_regulators() to accept a NULL argument and
update its users accordingly (Viresh Kumar).
- Add frequency changes tracepoint to devfreq (Matthias Kaehlcke).
- Add support for governor feature flags to devfreq, make devfreq
sysfs file permissions depend on the governor and clean up the
devfreq core (Chanwoo Choi).
- Clean up the tegra20 devfreq driver and deprecate it to allow
another driver based on EMC_STAT to be used instead of it (Dmitry
Osipenko).
- Add interconnect support to the tegra30 devfreq driver, allow it to
take the interconnect and OPP information from DT and clean it up
(Dmitry Osipenko).
- Add interconnect support to the exynos-bus devfreq driver along
with interconnect properties documentation (Sylwester Nawrocki).
- Add suport for AMD Fam17h and Fam19h processors to the RAPL power
capping driver (Victor Ding, Kim Phillips).
- Fix handling of overly long constraint names in the powercap
framework (Lukasz Luba).
- Fix the wakeup configuration handling for bridges in the ACPI
device power management core (Rafael Wysocki).
- Add support for using an abstract scale for power units in the
Energy Model (EM) and document it (Lukasz Luba).
- Add em_cpu_energy() micro-optimization to the EM (Pavankumar
Kondeti).
- Modify the generic power domains (genpd) framwework to support
suspend-to-idle (Ulf Hansson).
- Fix creation of debugfs nodes in genpd (Thierry Strudel).
- Clean up genpd (Lina Iyer).
- Clean up the core system-wide suspend code and make it print driver
flags for devices with debug enabled (Alex Shi, Patrice Chotard,
Chen Yu).
- Modify the ACPI system reboot code to make it prepare for system
power off to avoid confusing the platform firmware (Kai-Heng Feng).
- Update the pm-graph (multiple changes, mostly usability-related)
and cpupower (online and offline CPU information support) PM
utilities (Todd Brandt, Brahadambal Srinivasan)"
* tag 'pm-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (86 commits)
cpufreq: Fix cpufreq_online() return value on errors
cpufreq: Fix up several kerneldoc comments
cpufreq: stats: Use local_clock() instead of jiffies
cpufreq: schedutil: Simplify sugov_update_next_freq()
cpufreq: intel_pstate: Simplify intel_cpufreq_update_pstate()
PM: domains: create debugfs nodes when adding power domains
opp: of: Allow empty opp-table with opp-shared
dt-bindings: opp: Allow empty OPP tables
media: venus: dev_pm_opp_put_*() accepts NULL argument
drm/panfrost: dev_pm_opp_put_*() accepts NULL argument
drm/lima: dev_pm_opp_put_*() accepts NULL argument
PM / devfreq: exynos: dev_pm_opp_put_*() accepts NULL argument
cpufreq: qcom-cpufreq-nvmem: dev_pm_opp_put_*() accepts NULL argument
cpufreq: dt: dev_pm_opp_put_regulators() accepts NULL argument
opp: Allow dev_pm_opp_put_*() APIs to accept NULL opp_table
opp: Don't create an OPP table from dev_pm_opp_get_opp_table()
cpufreq: dt: Don't (ab)use dev_pm_opp_get_opp_table() to create OPP table
opp: Reduce the size of critical section in _opp_kref_release()
PM / EM: Micro optimization in em_cpu_energy
cpufreq: arm_scmi: Discover the power scale in performance protocol
...
244 lines
5.4 KiB
C
244 lines
5.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
|
*
|
|
* Based on panfrost_devfreq.c:
|
|
* Copyright 2019 Collabora ltd.
|
|
*/
|
|
#include <linux/clk.h>
|
|
#include <linux/devfreq.h>
|
|
#include <linux/devfreq_cooling.h>
|
|
#include <linux/device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm_opp.h>
|
|
#include <linux/property.h>
|
|
|
|
#include "lima_device.h"
|
|
#include "lima_devfreq.h"
|
|
|
|
static void lima_devfreq_update_utilization(struct lima_devfreq *devfreq)
|
|
{
|
|
ktime_t now, last;
|
|
|
|
now = ktime_get();
|
|
last = devfreq->time_last_update;
|
|
|
|
if (devfreq->busy_count > 0)
|
|
devfreq->busy_time += ktime_sub(now, last);
|
|
else
|
|
devfreq->idle_time += ktime_sub(now, last);
|
|
|
|
devfreq->time_last_update = now;
|
|
}
|
|
|
|
static int lima_devfreq_target(struct device *dev, unsigned long *freq,
|
|
u32 flags)
|
|
{
|
|
struct dev_pm_opp *opp;
|
|
|
|
opp = devfreq_recommended_opp(dev, freq, flags);
|
|
if (IS_ERR(opp))
|
|
return PTR_ERR(opp);
|
|
dev_pm_opp_put(opp);
|
|
|
|
return dev_pm_opp_set_rate(dev, *freq);
|
|
}
|
|
|
|
static void lima_devfreq_reset(struct lima_devfreq *devfreq)
|
|
{
|
|
devfreq->busy_time = 0;
|
|
devfreq->idle_time = 0;
|
|
devfreq->time_last_update = ktime_get();
|
|
}
|
|
|
|
static int lima_devfreq_get_dev_status(struct device *dev,
|
|
struct devfreq_dev_status *status)
|
|
{
|
|
struct lima_device *ldev = dev_get_drvdata(dev);
|
|
struct lima_devfreq *devfreq = &ldev->devfreq;
|
|
unsigned long irqflags;
|
|
|
|
status->current_frequency = clk_get_rate(ldev->clk_gpu);
|
|
|
|
spin_lock_irqsave(&devfreq->lock, irqflags);
|
|
|
|
lima_devfreq_update_utilization(devfreq);
|
|
|
|
status->total_time = ktime_to_ns(ktime_add(devfreq->busy_time,
|
|
devfreq->idle_time));
|
|
status->busy_time = ktime_to_ns(devfreq->busy_time);
|
|
|
|
lima_devfreq_reset(devfreq);
|
|
|
|
spin_unlock_irqrestore(&devfreq->lock, irqflags);
|
|
|
|
dev_dbg(ldev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
|
|
status->busy_time, status->total_time,
|
|
status->busy_time / (status->total_time / 100),
|
|
status->current_frequency / 1000 / 1000);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct devfreq_dev_profile lima_devfreq_profile = {
|
|
.polling_ms = 50, /* ~3 frames */
|
|
.target = lima_devfreq_target,
|
|
.get_dev_status = lima_devfreq_get_dev_status,
|
|
};
|
|
|
|
void lima_devfreq_fini(struct lima_device *ldev)
|
|
{
|
|
struct lima_devfreq *devfreq = &ldev->devfreq;
|
|
|
|
if (devfreq->cooling) {
|
|
devfreq_cooling_unregister(devfreq->cooling);
|
|
devfreq->cooling = NULL;
|
|
}
|
|
|
|
if (devfreq->devfreq) {
|
|
devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
|
|
devfreq->devfreq = NULL;
|
|
}
|
|
|
|
dev_pm_opp_of_remove_table(ldev->dev);
|
|
|
|
dev_pm_opp_put_regulators(devfreq->regulators_opp_table);
|
|
dev_pm_opp_put_clkname(devfreq->clkname_opp_table);
|
|
devfreq->regulators_opp_table = NULL;
|
|
devfreq->clkname_opp_table = NULL;
|
|
}
|
|
|
|
int lima_devfreq_init(struct lima_device *ldev)
|
|
{
|
|
struct thermal_cooling_device *cooling;
|
|
struct device *dev = ldev->dev;
|
|
struct opp_table *opp_table;
|
|
struct devfreq *devfreq;
|
|
struct lima_devfreq *ldevfreq = &ldev->devfreq;
|
|
struct dev_pm_opp *opp;
|
|
unsigned long cur_freq;
|
|
int ret;
|
|
|
|
if (!device_property_present(dev, "operating-points-v2"))
|
|
/* Optional, continue without devfreq */
|
|
return 0;
|
|
|
|
spin_lock_init(&ldevfreq->lock);
|
|
|
|
opp_table = dev_pm_opp_set_clkname(dev, "core");
|
|
if (IS_ERR(opp_table)) {
|
|
ret = PTR_ERR(opp_table);
|
|
goto err_fini;
|
|
}
|
|
|
|
ldevfreq->clkname_opp_table = opp_table;
|
|
|
|
opp_table = dev_pm_opp_set_regulators(dev,
|
|
(const char *[]){ "mali" },
|
|
1);
|
|
if (IS_ERR(opp_table)) {
|
|
ret = PTR_ERR(opp_table);
|
|
|
|
/* Continue if the optional regulator is missing */
|
|
if (ret != -ENODEV)
|
|
goto err_fini;
|
|
} else {
|
|
ldevfreq->regulators_opp_table = opp_table;
|
|
}
|
|
|
|
ret = dev_pm_opp_of_add_table(dev);
|
|
if (ret)
|
|
goto err_fini;
|
|
|
|
lima_devfreq_reset(ldevfreq);
|
|
|
|
cur_freq = clk_get_rate(ldev->clk_gpu);
|
|
|
|
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
|
|
if (IS_ERR(opp)) {
|
|
ret = PTR_ERR(opp);
|
|
goto err_fini;
|
|
}
|
|
|
|
lima_devfreq_profile.initial_freq = cur_freq;
|
|
dev_pm_opp_put(opp);
|
|
|
|
devfreq = devm_devfreq_add_device(dev, &lima_devfreq_profile,
|
|
DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
|
|
if (IS_ERR(devfreq)) {
|
|
dev_err(dev, "Couldn't initialize GPU devfreq\n");
|
|
ret = PTR_ERR(devfreq);
|
|
goto err_fini;
|
|
}
|
|
|
|
ldevfreq->devfreq = devfreq;
|
|
|
|
cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
|
|
if (IS_ERR(cooling))
|
|
dev_info(dev, "Failed to register cooling device\n");
|
|
else
|
|
ldevfreq->cooling = cooling;
|
|
|
|
return 0;
|
|
|
|
err_fini:
|
|
lima_devfreq_fini(ldev);
|
|
return ret;
|
|
}
|
|
|
|
void lima_devfreq_record_busy(struct lima_devfreq *devfreq)
|
|
{
|
|
unsigned long irqflags;
|
|
|
|
if (!devfreq->devfreq)
|
|
return;
|
|
|
|
spin_lock_irqsave(&devfreq->lock, irqflags);
|
|
|
|
lima_devfreq_update_utilization(devfreq);
|
|
|
|
devfreq->busy_count++;
|
|
|
|
spin_unlock_irqrestore(&devfreq->lock, irqflags);
|
|
}
|
|
|
|
void lima_devfreq_record_idle(struct lima_devfreq *devfreq)
|
|
{
|
|
unsigned long irqflags;
|
|
|
|
if (!devfreq->devfreq)
|
|
return;
|
|
|
|
spin_lock_irqsave(&devfreq->lock, irqflags);
|
|
|
|
lima_devfreq_update_utilization(devfreq);
|
|
|
|
WARN_ON(--devfreq->busy_count < 0);
|
|
|
|
spin_unlock_irqrestore(&devfreq->lock, irqflags);
|
|
}
|
|
|
|
int lima_devfreq_resume(struct lima_devfreq *devfreq)
|
|
{
|
|
unsigned long irqflags;
|
|
|
|
if (!devfreq->devfreq)
|
|
return 0;
|
|
|
|
spin_lock_irqsave(&devfreq->lock, irqflags);
|
|
|
|
lima_devfreq_reset(devfreq);
|
|
|
|
spin_unlock_irqrestore(&devfreq->lock, irqflags);
|
|
|
|
return devfreq_resume_device(devfreq->devfreq);
|
|
}
|
|
|
|
int lima_devfreq_suspend(struct lima_devfreq *devfreq)
|
|
{
|
|
if (!devfreq->devfreq)
|
|
return 0;
|
|
|
|
return devfreq_suspend_device(devfreq->devfreq);
|
|
}
|