mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
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:
commit
22b65d31ad
@ -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";
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user