Merge branches 'pm-domains' and 'pm-devfreq'

* pm-domains:
  PM: domains: Drop/restore performance state votes for devices at runtime PM
  PM: domains: Return early if perf state is already set for the device
  PM: domains: Split code in dev_pm_genpd_set_performance_state()
  PM: domains: fix some kernel-doc issues

* pm-devfreq:
  PM / devfreq: passive: Fix get_target_freq when not using required-opp
  dt-bindings: devfreq: tegra30-actmon: Add cooling-cells
  dt-bindings: devfreq: tegra30-actmon: Convert to schema
  PM / devfreq: userspace: Use DEVICE_ATTR_RW macro
  PM / devfreq: imx8m-ddrc: Remove DEVFREQ_GOV_SIMPLE_ONDEMAND dependency
  PM / devfreq: tegra30: Support thermal cooling
  PM / devfreq: imx-bus: Remove imx_bus_get_dev_status
  PM / devfreq: Add missing error code in devfreq_add_device()
This commit is contained in:
Rafael J. Wysocki 2021-06-29 15:53:19 +02:00
commit 22b65d31ad
11 changed files with 186 additions and 93 deletions

View File

@ -1,57 +0,0 @@
NVIDIA Tegra Activity Monitor
The activity monitor block collects statistics about the behaviour of other
components in the system. This information can be used to derive the rate at
which the external memory needs to be clocked in order to serve all requests
from the monitored clients.
Required properties:
- compatible: should be "nvidia,tegra<chip>-actmon"
- reg: offset and length of the register set for the device
- interrupts: standard interrupt property
- clocks: Must contain a phandle and clock specifier pair for each entry in
clock-names. See ../../clock/clock-bindings.txt for details.
- clock-names: Must include the following entries:
- actmon
- emc
- resets: Must contain an entry for each entry in reset-names. See
../../reset/reset.txt for details.
- reset-names: Must include the following entries:
- actmon
- operating-points-v2: See ../bindings/opp/opp.txt for details.
- interconnects: Should contain entries for memory clients sitting on
MC->EMC memory interconnect path.
- interconnect-names: Should include name of the interconnect path for each
interconnect entry. Consult TRM documentation for
information about available memory clients, see MEMORY
CONTROLLER section.
For each opp entry in 'operating-points-v2' table:
- opp-supported-hw: bitfield indicating SoC speedo ID mask
- opp-peak-kBps: peak bandwidth of the memory channel
Example:
dfs_opp_table: opp-table {
compatible = "operating-points-v2";
opp@12750000 {
opp-hz = /bits/ 64 <12750000>;
opp-supported-hw = <0x000F>;
opp-peak-kBps = <51000>;
};
...
};
actmon@6000c800 {
compatible = "nvidia,tegra124-actmon";
reg = <0x0 0x6000c800 0x0 0x400>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_ACTMON>,
<&tegra_car TEGRA124_CLK_EMC>;
clock-names = "actmon", "emc";
resets = <&tegra_car 119>;
reset-names = "actmon";
operating-points-v2 = <&dfs_opp_table>;
interconnects = <&mc TEGRA124_MC_MPCORER &emc>;
interconnect-names = "cpu";
};

View File

@ -0,0 +1,126 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/devfreq/nvidia,tegra30-actmon.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra30 Activity Monitor
maintainers:
- Dmitry Osipenko <digetx@gmail.com>
- Jon Hunter <jonathanh@nvidia.com>
- Thierry Reding <thierry.reding@gmail.com>
description: |
The activity monitor block collects statistics about the behaviour of other
components in the system. This information can be used to derive the rate at
which the external memory needs to be clocked in order to serve all requests
from the monitored clients.
properties:
compatible:
enum:
- nvidia,tegra30-actmon
- nvidia,tegra114-actmon
- nvidia,tegra124-actmon
- nvidia,tegra210-actmon
reg:
maxItems: 1
clocks:
maxItems: 2
clock-names:
items:
- const: actmon
- const: emc
resets:
maxItems: 1
reset-names:
items:
- const: actmon
interrupts:
maxItems: 1
interconnects:
minItems: 1
maxItems: 12
interconnect-names:
minItems: 1
maxItems: 12
description:
Should include name of the interconnect path for each interconnect
entry. Consult TRM documentation for information about available
memory clients, see MEMORY CONTROLLER and ACTIVITY MONITOR sections.
operating-points-v2:
description:
Should contain freqs and voltages and opp-supported-hw property, which
is a bitfield indicating SoC speedo ID mask.
"#cooling-cells":
const: 2
required:
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
- interrupts
- interconnects
- interconnect-names
- operating-points-v2
- "#cooling-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/memory/tegra30-mc.h>
mc: memory-controller@7000f000 {
compatible = "nvidia,tegra30-mc";
reg = <0x7000f000 0x400>;
clocks = <&clk 32>;
clock-names = "mc";
interrupts = <0 77 4>;
#iommu-cells = <1>;
#reset-cells = <1>;
#interconnect-cells = <1>;
};
emc: external-memory-controller@7000f400 {
compatible = "nvidia,tegra30-emc";
reg = <0x7000f400 0x400>;
interrupts = <0 78 4>;
clocks = <&clk 57>;
nvidia,memory-controller = <&mc>;
operating-points-v2 = <&dvfs_opp_table>;
power-domains = <&domain>;
#interconnect-cells = <0>;
};
actmon@6000c800 {
compatible = "nvidia,tegra30-actmon";
reg = <0x6000c800 0x400>;
interrupts = <0 45 4>;
clocks = <&clk 119>, <&clk 57>;
clock-names = "actmon", "emc";
resets = <&rst 119>;
reset-names = "actmon";
operating-points-v2 = <&dvfs_opp_table>;
interconnects = <&mc TEGRA30_MC_MPCORER &emc>;
interconnect-names = "cpu-read";
#cooling-cells = <2>;
};

View File

@ -379,6 +379,44 @@ err:
return ret;
}
static int genpd_set_performance_state(struct device *dev, unsigned int state)
{
struct generic_pm_domain *genpd = dev_to_genpd(dev);
struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
unsigned int prev_state;
int ret;
prev_state = gpd_data->performance_state;
if (prev_state == state)
return 0;
gpd_data->performance_state = state;
state = _genpd_reeval_performance_state(genpd, state);
ret = _genpd_set_performance_state(genpd, state, 0);
if (ret)
gpd_data->performance_state = prev_state;
return ret;
}
static int genpd_drop_performance_state(struct device *dev)
{
unsigned int prev_state = dev_gpd_data(dev)->performance_state;
if (!genpd_set_performance_state(dev, 0))
return prev_state;
return 0;
}
static void genpd_restore_performance_state(struct device *dev,
unsigned int state)
{
if (state)
genpd_set_performance_state(dev, state);
}
/**
* dev_pm_genpd_set_performance_state- Set performance state of device's power
* domain.
@ -397,8 +435,6 @@ err:
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
{
struct generic_pm_domain *genpd;
struct generic_pm_domain_data *gpd_data;
unsigned int prev;
int ret;
genpd = dev_to_genpd_safe(dev);
@ -410,16 +446,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
return -EINVAL;
genpd_lock(genpd);
gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
prev = gpd_data->performance_state;
gpd_data->performance_state = state;
state = _genpd_reeval_performance_state(genpd, state);
ret = _genpd_set_performance_state(genpd, state, 0);
if (ret)
gpd_data->performance_state = prev;
ret = genpd_set_performance_state(dev, state);
genpd_unlock(genpd);
return ret;
@ -572,6 +599,7 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
* RPM status of the releated device is in an intermediate state, not yet turned
* into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not
* be RPM_SUSPENDED, while it tries to power off the PM domain.
* @depth: nesting count for lockdep.
*
* If all of the @genpd's devices have been suspended and all of its subdomains
* have been powered down, remove power from @genpd.
@ -832,7 +860,8 @@ static int genpd_runtime_suspend(struct device *dev)
{
struct generic_pm_domain *genpd;
bool (*suspend_ok)(struct device *__dev);
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
struct gpd_timing_data *td = &gpd_data->td;
bool runtime_pm = pm_runtime_enabled(dev);
ktime_t time_start;
s64 elapsed_ns;
@ -889,6 +918,7 @@ static int genpd_runtime_suspend(struct device *dev)
return 0;
genpd_lock(genpd);
gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_power_off(genpd, true, 0);
genpd_unlock(genpd);
@ -906,7 +936,8 @@ static int genpd_runtime_suspend(struct device *dev)
static int genpd_runtime_resume(struct device *dev)
{
struct generic_pm_domain *genpd;
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
struct gpd_timing_data *td = &gpd_data->td;
bool runtime_pm = pm_runtime_enabled(dev);
ktime_t time_start;
s64 elapsed_ns;
@ -930,6 +961,8 @@ static int genpd_runtime_resume(struct device *dev)
genpd_lock(genpd);
ret = genpd_power_on(genpd, 0);
if (!ret)
genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
genpd_unlock(genpd);
if (ret)
@ -968,6 +1001,7 @@ err_stop:
err_poweroff:
if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) {
genpd_lock(genpd);
gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_power_off(genpd, true, 0);
genpd_unlock(genpd);
}
@ -2505,7 +2539,7 @@ EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain);
/**
* of_genpd_remove_last - Remove the last PM domain registered for a provider
* @provider: Pointer to device structure associated with provider
* @np: Pointer to device node associated with provider
*
* Find the last PM domain that was added by a particular provider and
* remove this PM domain from the list of PM domains. The provider is

View File

@ -252,6 +252,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
/**
* _default_power_down_ok - Default generic PM domain power off governor routine.
* @pd: PM domain to check.
* @now: current ktime.
*
* This routine must be executed under the PM domain's lock.
*/

View File

@ -103,7 +103,6 @@ config ARM_IMX8M_DDRC_DEVFREQ
tristate "i.MX8M DDRC DEVFREQ Driver"
depends on (ARCH_MXC && HAVE_ARM_SMCCC) || \
(COMPILE_TEST && HAVE_ARM_SMCCC)
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select DEVFREQ_GOV_USERSPACE
help
This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows

View File

@ -823,6 +823,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
if (devfreq->profile->timer < 0
|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
mutex_unlock(&devfreq->lock);
err = -EINVAL;
goto err_dev;
}

View File

@ -65,7 +65,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
dev_pm_opp_put(p_opp);
if (IS_ERR(opp))
return PTR_ERR(opp);
goto no_required_opp;
*freq = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
@ -73,6 +73,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
return 0;
}
no_required_opp:
/*
* Get the OPP table's index of decided frequency by governor
* of parent device.

View File

@ -31,7 +31,7 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
return 0;
}
static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
static ssize_t set_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *devfreq = to_devfreq(dev);
@ -52,8 +52,8 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
return err;
}
static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
char *buf)
static ssize_t set_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
struct userspace_data *data;
@ -70,7 +70,7 @@ static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
return err;
}
static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
static DEVICE_ATTR_RW(set_freq);
static struct attribute *dev_entries[] = {
&dev_attr_set_freq.attr,
NULL,

View File

@ -45,18 +45,6 @@ static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
return 0;
}
static int imx_bus_get_dev_status(struct device *dev,
struct devfreq_dev_status *stat)
{
struct imx_bus *priv = dev_get_drvdata(dev);
stat->busy_time = 0;
stat->total_time = 0;
stat->current_frequency = clk_get_rate(priv->clk);
return 0;
}
static void imx_bus_exit(struct device *dev)
{
struct imx_bus *priv = dev_get_drvdata(dev);
@ -129,9 +117,7 @@ static int imx_bus_probe(struct platform_device *pdev)
return ret;
}
priv->profile.polling_ms = 1000;
priv->profile.target = imx_bus_target;
priv->profile.get_dev_status = imx_bus_get_dev_status;
priv->profile.exit = imx_bus_exit;
priv->profile.get_cur_freq = imx_bus_get_cur_freq;
priv->profile.initial_freq = clk_get_rate(priv->clk);

View File

@ -688,6 +688,7 @@ static struct devfreq_dev_profile tegra_devfreq_profile = {
.polling_ms = ACTMON_SAMPLING_PERIOD,
.target = tegra_devfreq_target,
.get_dev_status = tegra_devfreq_get_dev_status,
.is_cooling_device = true,
};
static int tegra_governor_get_target(struct devfreq *devfreq,

View File

@ -198,6 +198,7 @@ struct generic_pm_domain_data {
struct notifier_block *power_nb;
int cpu;
unsigned int performance_state;
unsigned int rpm_pstate;
ktime_t next_wakeup;
void *data;
};