diff options
-rw-r--r-- | Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml | 1 | ||||
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-psci.c | 3 | ||||
-rw-r--r-- | drivers/pmdomain/bcm/bcm2835-power.c | 1 | ||||
-rw-r--r-- | drivers/pmdomain/core.c | 35 | ||||
-rw-r--r-- | drivers/pmdomain/imx/gpcv2.c | 2 | ||||
-rw-r--r-- | drivers/pmdomain/renesas/rcar-sysc.c | 2 | ||||
-rw-r--r-- | drivers/pmdomain/rockchip/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pmdomain/rockchip/pm-domains.c | 9 | ||||
-rw-r--r-- | drivers/pmdomain/sunxi/sun20i-ppu.c | 15 | ||||
-rw-r--r-- | drivers/pmdomain/ti/omap_prm.c | 2 | ||||
-rw-r--r-- | include/dt-bindings/power/allwinner,sun8i-v853-ppu.h | 10 | ||||
-rw-r--r-- | include/dt-bindings/power/qcom-rpmpd.h | 2 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 7 | ||||
-rw-r--r-- | include/soc/rockchip/rockchip_sip.h | 3 | ||||
-rw-r--r-- | include/trace/events/power.h | 37 |
16 files changed, 127 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml b/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml index 46e2647a5d72..f578be6a3bc8 100644 --- a/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml +++ b/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - allwinner,sun20i-d1-ppu + - allwinner,sun8i-v853-ppu reg: maxItems: 1 diff --git a/MAINTAINERS b/MAINTAINERS index 4ff26fa94895..fd1859bcf45e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6080,9 +6080,11 @@ F: include/linux/platform_data/cpuidle-exynos.h CPUIDLE DRIVER - ARM PSCI M: Lorenzo Pieralisi <lpieralisi@kernel.org> M: Sudeep Holla <sudeep.holla@arm.com> +M: Ulf Hansson <ulf.hansson@linaro.org> L: linux-pm@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git F: drivers/cpuidle/cpuidle-psci.c CPUIDLE DRIVER - ARM PSCI PM DOMAIN diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c index 2562dc001fc1..dd8d776d6e39 100644 --- a/drivers/cpuidle/cpuidle-psci.c +++ b/drivers/cpuidle/cpuidle-psci.c @@ -25,6 +25,7 @@ #include <linux/syscore_ops.h> #include <asm/cpuidle.h> +#include <trace/events/power.h> #include "cpuidle-psci.h" #include "dt_idle_states.h" @@ -74,7 +75,9 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, if (!state) state = states[idx]; + trace_psci_domain_idle_enter(dev->cpu, state, s2idle); ret = psci_cpu_suspend_enter(state) ? -1 : idx; + trace_psci_domain_idle_exit(dev->cpu, state, s2idle); if (s2idle) dev_pm_genpd_resume(pd_dev); diff --git a/drivers/pmdomain/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c index d2f0233cb620..d3cd816979ac 100644 --- a/drivers/pmdomain/bcm/bcm2835-power.c +++ b/drivers/pmdomain/bcm/bcm2835-power.c @@ -520,6 +520,7 @@ bcm2835_init_power_domain(struct bcm2835_power *power, } dom->base.name = name; + dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP; dom->base.power_on = bcm2835_power_pd_power_on; dom->base.power_off = bcm2835_power_pd_power_off; diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 6c94137865c9..9b2f28b34bb5 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -697,6 +697,37 @@ bool dev_pm_genpd_get_hwmode(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode); +/** + * dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off. + * + * @dev: Device for which the PM domain may need to stay on for. + * @on: Value to set or unset for the condition. + * + * For some usecases a consumer driver requires its device to remain power-on + * from the PM domain perspective during runtime. This function allows the + * behaviour to be dynamically controlled for a device attached to a genpd. + * + * It is assumed that the users guarantee that the genpd wouldn't be detached + * while this routine is getting called. + * + * Return: Returns 0 on success and negative error values on failures. + */ +int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) +{ + struct generic_pm_domain *genpd; + + genpd = dev_to_genpd_safe(dev); + if (!genpd) + return -ENODEV; + + genpd_lock(genpd); + dev_gpd_data(dev)->rpm_always_on = on; + genpd_unlock(genpd); + + return 0; +} +EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on); + static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) { unsigned int state_idx = genpd->state_idx; @@ -868,6 +899,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, if (!pm_runtime_suspended(pdd->dev) || irq_safe_dev_in_sleep_domain(pdd->dev, genpd)) not_suspended++; + + /* The device may need its PM domain to stay powered on. */ + if (to_gpd_data(pdd)->rpm_always_on) + return -EBUSY; } if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on)) diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c index 958d34d4821b..105fcaf13a34 100644 --- a/drivers/pmdomain/imx/gpcv2.c +++ b/drivers/pmdomain/imx/gpcv2.c @@ -1361,7 +1361,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) } if (IS_ENABLED(CONFIG_LOCKDEP) && - of_property_read_bool(domain->dev->of_node, "power-domains")) + of_property_present(domain->dev->of_node, "power-domains")) lockdep_set_subclass(&domain->genpd.mlock, 1); ret = of_genpd_add_provider_simple(domain->dev->of_node, diff --git a/drivers/pmdomain/renesas/rcar-sysc.c b/drivers/pmdomain/renesas/rcar-sysc.c index b99326917330..dce1a6d37e80 100644 --- a/drivers/pmdomain/renesas/rcar-sysc.c +++ b/drivers/pmdomain/renesas/rcar-sysc.c @@ -434,8 +434,6 @@ static int __init rcar_sysc_pd_init(void) } error = of_genpd_add_provider_onecell(np, &domains->onecell_data); - if (!error) - fwnode_dev_initialized(of_fwnode_handle(np), true); out_put: of_node_put(np); diff --git a/drivers/pmdomain/rockchip/Kconfig b/drivers/pmdomain/rockchip/Kconfig index b0d70f1a8439..7e4f9b628f0b 100644 --- a/drivers/pmdomain/rockchip/Kconfig +++ b/drivers/pmdomain/rockchip/Kconfig @@ -4,6 +4,7 @@ if ARCH_ROCKCHIP || COMPILE_TEST config ROCKCHIP_PM_DOMAINS bool "Rockchip generic power domain" depends on PM + depends on HAVE_ARM_SMCCC_DISCOVERY select PM_GENERIC_DOMAINS help Say y here to enable power domain support. diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c index cb0f93800138..27a5c68ff8ba 100644 --- a/drivers/pmdomain/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c @@ -5,6 +5,7 @@ * Copyright (c) 2015 ROCKCHIP, Co. Ltd. */ +#include <linux/arm-smccc.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/err.h> @@ -20,6 +21,7 @@ #include <linux/regmap.h> #include <linux/mfd/syscon.h> #include <soc/rockchip/pm_domains.h> +#include <soc/rockchip/rockchip_sip.h> #include <dt-bindings/power/px30-power.h> #include <dt-bindings/power/rockchip,rv1126-power.h> #include <dt-bindings/power/rk3036-power.h> @@ -540,6 +542,7 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, struct generic_pm_domain *genpd = &pd->genpd; u32 pd_pwr_offset = pd->info->pwr_offset; bool is_on, is_mem_on = false; + struct arm_smccc_res res; if (pd->info->pwr_mask == 0) return; @@ -567,6 +570,12 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, genpd->name, is_on); return; } + + /* Inform firmware to keep this pd on or off */ + if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE) + arm_smccc_smc(ROCKCHIP_SIP_SUSPEND_MODE, ROCKCHIP_SLEEP_PD_CONFIG, + pmu->info->pwr_offset + pd_pwr_offset, + pd->info->pwr_mask, on, 0, 0, 0, &res); } static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) diff --git a/drivers/pmdomain/sunxi/sun20i-ppu.c b/drivers/pmdomain/sunxi/sun20i-ppu.c index 8700f9dd5f75..9f002748d224 100644 --- a/drivers/pmdomain/sunxi/sun20i-ppu.c +++ b/drivers/pmdomain/sunxi/sun20i-ppu.c @@ -182,11 +182,26 @@ static const struct sun20i_ppu_desc sun20i_d1_ppu_desc = { .num_domains = ARRAY_SIZE(sun20i_d1_ppu_pd_names), }; +static const char *const sun8i_v853_ppu_pd_names[] = { + "RISCV", + "NPU", + "VE", +}; + +static const struct sun20i_ppu_desc sun8i_v853_ppu_desc = { + .names = sun8i_v853_ppu_pd_names, + .num_domains = ARRAY_SIZE(sun8i_v853_ppu_pd_names), +}; + static const struct of_device_id sun20i_ppu_of_match[] = { { .compatible = "allwinner,sun20i-d1-ppu", .data = &sun20i_d1_ppu_desc, }, + { + .compatible = "allwinner,sun8i-v853-ppu", + .data = &sun8i_v853_ppu_desc, + }, { } }; MODULE_DEVICE_TABLE(of, sun20i_ppu_of_match); diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c index b8ceb3c2b81c..79d165331d8c 100644 --- a/drivers/pmdomain/ti/omap_prm.c +++ b/drivers/pmdomain/ti/omap_prm.c @@ -613,7 +613,7 @@ static int omap_prm_domain_attach_clock(struct device *dev, if (!of_device_is_compatible(np, "simple-pm-bus")) return 0; - if (!of_property_read_bool(np, "clocks")) + if (!of_property_present(np, "clocks")) return 0; error = pm_clk_create(dev); diff --git a/include/dt-bindings/power/allwinner,sun8i-v853-ppu.h b/include/dt-bindings/power/allwinner,sun8i-v853-ppu.h new file mode 100644 index 000000000000..b1c18a490613 --- /dev/null +++ b/include/dt-bindings/power/allwinner,sun8i-v853-ppu.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef _DT_BINDINGS_POWER_SUN8I_V853_PPU_H_ +#define _DT_BINDINGS_POWER_SUN8I_V853_PPU_H_ + +#define PD_RISCV 0 +#define PD_NPU 1 +#define PD_VE 2 + +#endif diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index df599bf46220..d9b7bac30953 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -65,7 +65,7 @@ #define SM6350_MSS 4 #define SM6350_MX 5 -/* SM6350 Power Domain Indexes */ +/* SM6375 Power Domain Indexes */ #define SM6375_VDDCX 0 #define SM6375_VDDCX_AO 1 #define SM6375_VDDCX_VFL 2 diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 1aab31370065..d56a78af4af1 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -261,6 +261,7 @@ struct generic_pm_domain_data { unsigned int rpm_pstate; unsigned int opp_token; bool hw_mode; + bool rpm_always_on; void *data; }; @@ -293,6 +294,7 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); void dev_pm_genpd_synced_poweroff(struct device *dev); int dev_pm_genpd_set_hwmode(struct device *dev, bool enable); bool dev_pm_genpd_get_hwmode(struct device *dev); +int dev_pm_genpd_rpm_always_on(struct device *dev, bool on); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; @@ -376,6 +378,11 @@ static inline bool dev_pm_genpd_get_hwmode(struct device *dev) return false; } +static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) +{ + return -EOPNOTSUPP; +} + #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) #endif diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h index c46a9ae2a2ab..501ad1fedb20 100644 --- a/include/soc/rockchip/rockchip_sip.h +++ b/include/soc/rockchip/rockchip_sip.h @@ -6,6 +6,9 @@ #ifndef __SOC_ROCKCHIP_SIP_H #define __SOC_ROCKCHIP_SIP_H +#define ROCKCHIP_SIP_SUSPEND_MODE 0x82000003 +#define ROCKCHIP_SLEEP_PD_CONFIG 0xff + #define ROCKCHIP_SIP_DRAM_FREQ 0x82000008 #define ROCKCHIP_SIP_CONFIG_DRAM_INIT 0x00 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE 0x01 diff --git a/include/trace/events/power.h b/include/trace/events/power.h index d2349b6b531a..9253e83b9bb4 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -62,6 +62,43 @@ TRACE_EVENT(cpu_idle_miss, (unsigned long)__entry->state, (__entry->below)?"below":"above") ); +DECLARE_EVENT_CLASS(psci_domain_idle, + + TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle), + + TP_ARGS(cpu_id, state, s2idle), + + TP_STRUCT__entry( + __field(u32, cpu_id) + __field(u32, state) + __field(bool, s2idle) + ), + + TP_fast_assign( + __entry->cpu_id = cpu_id; + __entry->state = state; + __entry->s2idle = s2idle; + ), + + TP_printk("cpu_id=%lu state=0x%lx is_s2idle=%s", + (unsigned long)__entry->cpu_id, (unsigned long)__entry->state, + (__entry->s2idle)?"yes":"no") +); + +DEFINE_EVENT(psci_domain_idle, psci_domain_idle_enter, + + TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle), + + TP_ARGS(cpu_id, state, s2idle) +); + +DEFINE_EVENT(psci_domain_idle, psci_domain_idle_exit, + + TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle), + + TP_ARGS(cpu_id, state, s2idle) +); + TRACE_EVENT(powernv_throttle, TP_PROTO(int chip_id, const char *reason, int pmax), |