diff options
-rw-r--r-- | Documentation/devicetree/bindings/power/rockchip,power-controller.yaml | 1 | ||||
-rw-r--r-- | drivers/base/power/common.c | 45 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-psci-domain.c | 17 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-psci.c | 26 | ||||
-rw-r--r-- | drivers/cpuidle/dt_idle_genpd.c | 14 | ||||
-rw-r--r-- | drivers/media/platform/qcom/venus/pm_helpers.c | 5 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/Makefile | 1 | ||||
-rw-r--r-- | drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c | 380 | ||||
-rw-r--r-- | drivers/pmdomain/apple/pmgr-pwrstate.c | 2 | ||||
-rw-r--r-- | drivers/pmdomain/bcm/raspberrypi-power.c | 43 | ||||
-rw-r--r-- | drivers/pmdomain/core.c | 75 | ||||
-rw-r--r-- | drivers/pmdomain/rockchip/pm-domains.c | 45 | ||||
-rw-r--r-- | include/dt-bindings/power/rockchip,rk3576-power.h | 30 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 16 |
15 files changed, 245 insertions, 466 deletions
diff --git a/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml b/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml index 0d5e999a58f1..650dc0aae6f5 100644 --- a/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml +++ b/Documentation/devicetree/bindings/power/rockchip,power-controller.yaml @@ -41,6 +41,7 @@ properties: - rockchip,rk3368-power-controller - rockchip,rk3399-power-controller - rockchip,rk3568-power-controller + - rockchip,rk3576-power-controller - rockchip,rk3588-power-controller - rockchip,rv1126-power-controller diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 327d168dd37a..8c34ae1cd8d5 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -277,6 +277,51 @@ err_attach: EXPORT_SYMBOL_GPL(dev_pm_domain_attach_list); /** + * devm_pm_domain_detach_list - devres-enabled version of dev_pm_domain_detach_list. + * @_list: The list of PM domains to detach. + * + * This function reverse the actions from devm_pm_domain_attach_list(). + * it will be invoked during the remove phase from drivers implicitly if driver + * uses devm_pm_domain_attach_list() to attach the PM domains. + */ +static void devm_pm_domain_detach_list(void *_list) +{ + struct dev_pm_domain_list *list = _list; + + dev_pm_domain_detach_list(list); +} + +/** + * devm_pm_domain_attach_list - devres-enabled version of dev_pm_domain_attach_list + * @dev: The device used to lookup the PM domains for. + * @data: The data used for attaching to the PM domains. + * @list: An out-parameter with an allocated list of attached PM domains. + * + * NOTE: this will also handle calling devm_pm_domain_detach_list() for + * you during remove phase. + * + * Returns the number of attached PM domains or a negative error code in case of + * a failure. + */ +int devm_pm_domain_attach_list(struct device *dev, + const struct dev_pm_domain_attach_data *data, + struct dev_pm_domain_list **list) +{ + int ret, num_pds; + + num_pds = dev_pm_domain_attach_list(dev, data, list); + if (num_pds <= 0) + return num_pds; + + ret = devm_add_action_or_reset(dev, devm_pm_domain_detach_list, *list); + if (ret) + return ret; + + return num_pds; +} +EXPORT_SYMBOL_GPL(devm_pm_domain_attach_list); + +/** * dev_pm_domain_detach - Detach a device from its PM domain. * @dev: Device to detach. * @power_off: Used to indicate whether we should power off the device. diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c index fae958794339..146f97068022 100644 --- a/drivers/cpuidle/cpuidle-psci-domain.c +++ b/drivers/cpuidle/cpuidle-psci-domain.c @@ -67,12 +67,16 @@ static int psci_pd_init(struct device_node *np, bool use_osi) /* * Allow power off when OSI has been successfully enabled. - * PREEMPT_RT is not yet ready to enter domain idle states. + * On a PREEMPT_RT based configuration the domain idle states are + * supported, but only during system-wide suspend. */ - if (use_osi && !IS_ENABLED(CONFIG_PREEMPT_RT)) + if (use_osi) { pd->power_off = psci_pd_power_off; - else + if (IS_ENABLED(CONFIG_PREEMPT_RT)) + pd->flags |= GENPD_FLAG_RPM_ALWAYS_ON; + } else { pd->flags |= GENPD_FLAG_ALWAYS_ON; + } /* Use governor for CPU PM domains if it has some states to manage. */ pd_gov = pd->states ? &pm_domain_cpu_gov : NULL; @@ -138,7 +142,6 @@ static const struct of_device_id psci_of_match[] = { static int psci_cpuidle_domain_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct device_node *node; bool use_osi = psci_has_osi_support(); int ret = 0, pd_count = 0; @@ -149,15 +152,13 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev) * Parse child nodes for the "#power-domain-cells" property and * initialize a genpd/genpd-of-provider pair when it's found. */ - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (!of_property_present(node, "#power-domain-cells")) continue; ret = psci_pd_init(node, use_osi); - if (ret) { - of_node_put(node); + if (ret) goto exit; - } pd_count++; } diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c index 782030a27703..2562dc001fc1 100644 --- a/drivers/cpuidle/cpuidle-psci.c +++ b/drivers/cpuidle/cpuidle-psci.c @@ -37,6 +37,7 @@ struct psci_cpuidle_data { static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data); static DEFINE_PER_CPU(u32, domain_state); +static bool psci_cpuidle_use_syscore; static bool psci_cpuidle_use_cpuhp; void psci_set_domain_state(u32 state) @@ -166,6 +167,12 @@ static struct syscore_ops psci_idle_syscore_ops = { .resume = psci_idle_syscore_resume, }; +static void psci_idle_init_syscore(void) +{ + if (psci_cpuidle_use_syscore) + register_syscore_ops(&psci_idle_syscore_ops); +} + static void psci_idle_init_cpuhp(void) { int err; @@ -173,8 +180,6 @@ static void psci_idle_init_cpuhp(void) if (!psci_cpuidle_use_cpuhp) return; - register_syscore_ops(&psci_idle_syscore_ops); - err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING, "cpuidle/psci:online", psci_idle_cpuhp_up, @@ -222,22 +227,23 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv, if (!psci_has_osi_support()) return 0; - if (IS_ENABLED(CONFIG_PREEMPT_RT)) - return 0; - data->dev = dt_idle_attach_cpu(cpu, "psci"); if (IS_ERR_OR_NULL(data->dev)) return PTR_ERR_OR_ZERO(data->dev); + psci_cpuidle_use_syscore = true; + /* * Using the deepest state for the CPU to trigger a potential selection * of a shared state for the domain, assumes the domain states are all - * deeper states. + * deeper states. On PREEMPT_RT the hierarchical topology is limited to + * s2ram and s2idle. */ - drv->states[state_count - 1].flags |= CPUIDLE_FLAG_RCU_IDLE; - drv->states[state_count - 1].enter = psci_enter_domain_idle_state; drv->states[state_count - 1].enter_s2idle = psci_enter_s2idle_domain_idle_state; - psci_cpuidle_use_cpuhp = true; + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { + drv->states[state_count - 1].enter = psci_enter_domain_idle_state; + psci_cpuidle_use_cpuhp = true; + } return 0; } @@ -313,6 +319,7 @@ static void psci_cpu_deinit_idle(int cpu) struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu); dt_idle_detach_cpu(data->dev); + psci_cpuidle_use_syscore = false; psci_cpuidle_use_cpuhp = false; } @@ -409,6 +416,7 @@ static int psci_cpuidle_probe(struct platform_device *pdev) goto out_fail; } + psci_idle_init_syscore(); psci_idle_init_cpuhp(); return 0; diff --git a/drivers/cpuidle/dt_idle_genpd.c b/drivers/cpuidle/dt_idle_genpd.c index 1af63c189039..203e9b754aea 100644 --- a/drivers/cpuidle/dt_idle_genpd.c +++ b/drivers/cpuidle/dt_idle_genpd.c @@ -130,11 +130,10 @@ out: int dt_idle_pd_init_topology(struct device_node *np) { - struct device_node *node; struct of_phandle_args child, parent; int ret; - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0, &parent)) continue; @@ -143,10 +142,8 @@ int dt_idle_pd_init_topology(struct device_node *np) child.args_count = 0; ret = of_genpd_add_subdomain(&parent, &child); of_node_put(parent.np); - if (ret) { - of_node_put(node); + if (ret) return ret; - } } return 0; @@ -154,11 +151,10 @@ int dt_idle_pd_init_topology(struct device_node *np) int dt_idle_pd_remove_topology(struct device_node *np) { - struct device_node *node; struct of_phandle_args child, parent; int ret; - for_each_child_of_node(np, node) { + for_each_child_of_node_scoped(np, node) { if (of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0, &parent)) continue; @@ -167,10 +163,8 @@ int dt_idle_pd_remove_topology(struct device_node *np) child.args_count = 0; ret = of_genpd_remove_subdomain(&parent, &child); of_node_put(parent.np); - if (ret) { - of_node_put(node); + if (ret) return ret; - } } return 0; diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 4ce76ce6dd4d..ea8a2bd9419e 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -876,7 +876,7 @@ static int vcodec_domains_get(struct venus_core *core) if (!res->vcodec_pmdomains_num) goto skip_pmdomains; - ret = dev_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains); + ret = devm_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains); if (ret < 0) return ret; @@ -902,14 +902,11 @@ skip_pmdomains: return 0; opp_attach_err: - dev_pm_domain_detach_list(core->pmdomains); return ret; } static void vcodec_domains_put(struct venus_core *core) { - dev_pm_domain_detach_list(core->pmdomains); - if (!core->has_opp_table) return; diff --git a/drivers/pmdomain/amlogic/Kconfig b/drivers/pmdomain/amlogic/Kconfig index 2108729909b5..e72b664174af 100644 --- a/drivers/pmdomain/amlogic/Kconfig +++ b/drivers/pmdomain/amlogic/Kconfig @@ -1,17 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "Amlogic PM Domains" -config MESON_GX_PM_DOMAINS - tristate "Amlogic Meson GX Power Domains driver" - depends on ARCH_MESON || COMPILE_TEST - depends on PM && OF - default ARCH_MESON - select PM_GENERIC_DOMAINS - select PM_GENERIC_DOMAINS_OF - help - Say yes to expose Amlogic Meson GX Power Domains as - Generic Power Domains. - config MESON_EE_PM_DOMAINS tristate "Amlogic Meson Everything-Else Power Domains driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/pmdomain/amlogic/Makefile b/drivers/pmdomain/amlogic/Makefile index 3d58abd574f9..99f195f09957 100644 --- a/drivers/pmdomain/amlogic/Makefile +++ b/drivers/pmdomain/amlogic/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o diff --git a/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c b/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c deleted file mode 100644 index 6028e91664a4..000000000000 --- a/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) 2017 BayLibre, SAS - * Author: Neil Armstrong <[email protected]> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <linux/platform_device.h> -#include <linux/pm_domain.h> -#include <linux/bitfield.h> -#include <linux/regmap.h> -#include <linux/mfd/syscon.h> -#include <linux/of.h> -#include <linux/reset.h> -#include <linux/clk.h> -#include <linux/module.h> - -/* AO Offsets */ - -#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2) - -#define GEN_PWR_VPU_HDMI BIT(8) -#define GEN_PWR_VPU_HDMI_ISO BIT(9) - -/* HHI Offsets */ - -#define HHI_MEM_PD_REG0 (0x40 << 2) -#define HHI_VPU_MEM_PD_REG0 (0x41 << 2) -#define HHI_VPU_MEM_PD_REG1 (0x42 << 2) -#define HHI_VPU_MEM_PD_REG2 (0x4d << 2) - -struct meson_gx_pwrc_vpu { - struct generic_pm_domain genpd; - struct regmap *regmap_ao; - struct regmap *regmap_hhi; - struct reset_control *rstc; - struct clk *vpu_clk; - struct clk *vapb_clk; -}; - -static inline -struct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d) -{ - return container_of(d, struct meson_gx_pwrc_vpu, genpd); -} - -static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); - udelay(20); - - /* Power Down Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), BIT(i)); - udelay(5); - } - udelay(20); - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); - - msleep(20); - - clk_disable_unprepare(pd->vpu_clk); - clk_disable_unprepare(pd->vapb_clk); - - return 0; -} - -static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); - udelay(20); - - /* Power Down Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, - 0x3 << i, 0x3 << i); - udelay(5); - } - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), BIT(i)); - udelay(5); - } - udelay(20); - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); - - msleep(20); - - clk_disable_unprepare(pd->vpu_clk); - clk_disable_unprepare(pd->vapb_clk); - - return 0; -} - -static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd) -{ - int ret; - - ret = clk_prepare_enable(pd->vpu_clk); - if (ret) - return ret; - - ret = clk_prepare_enable(pd->vapb_clk); - if (ret) - clk_disable_unprepare(pd->vpu_clk); - - return ret; -} - -static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int ret; - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, 0); - udelay(20); - - /* Power Up Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0); - udelay(5); - } - - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), 0); - udelay(5); - } - udelay(20); - - ret = reset_control_assert(pd->rstc); - if (ret) - return ret; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, 0); - - ret = reset_control_deassert(pd->rstc); - if (ret) - return ret; - - ret = meson_gx_pwrc_vpu_setup_clk(pd); - if (ret) - return ret; - - return 0; -} - -static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd) -{ - struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); - int ret; - int i; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI, 0); - udelay(20); - - /* Power Up Memories */ - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x3 << i, 0); - udelay(5); - } - - for (i = 0; i < 32; i += 2) { - regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, - 0x3 << i, 0); - udelay(5); - } - - for (i = 8; i < 16; i++) { - regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, - BIT(i), 0); - udelay(5); - } - udelay(20); - - ret = reset_control_assert(pd->rstc); - if (ret) - return ret; - - regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, - GEN_PWR_VPU_HDMI_ISO, 0); - - ret = reset_control_deassert(pd->rstc); - if (ret) - return ret; - - ret = meson_gx_pwrc_vpu_setup_clk(pd); - if (ret) - return ret; - - return 0; -} - -static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd) -{ - u32 reg; - - regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ®); - - return (reg & GEN_PWR_VPU_HDMI); -} - -static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { - .genpd = { - .name = "vpu_hdmi", - .power_off = meson_gx_pwrc_vpu_power_off, - .power_on = meson_gx_pwrc_vpu_power_on, - }, -}; - -static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = { - .genpd = { - .name = "vpu_hdmi", - .power_off = meson_g12a_pwrc_vpu_power_off, - .power_on = meson_g12a_pwrc_vpu_power_on, - }, -}; - -static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) -{ - const struct meson_gx_pwrc_vpu *vpu_pd_match; - struct regmap *regmap_ao, *regmap_hhi; - struct meson_gx_pwrc_vpu *vpu_pd; - struct device_node *parent_np; - struct reset_control *rstc; - struct clk *vpu_clk; - struct clk *vapb_clk; - bool powered_off; - int ret; - - vpu_pd_match = of_device_get_match_data(&pdev->dev); - if (!vpu_pd_match) { - dev_err(&pdev->dev, "failed to get match data\n"); - return -ENODEV; - } - - vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL); - if (!vpu_pd) - return -ENOMEM; - - memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd)); - - parent_np = of_get_parent(pdev->dev.of_node); - regmap_ao = syscon_node_to_regmap(parent_np); - of_node_put(parent_np); - if (IS_ERR(regmap_ao)) { - dev_err(&pdev->dev, "failed to get regmap\n"); - return PTR_ERR(regmap_ao); - } - - regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "amlogic,hhi-sysctrl"); - if (IS_ERR(regmap_hhi)) { - dev_err(&pdev->dev, "failed to get HHI regmap\n"); - return PTR_ERR(regmap_hhi); - } - - rstc = devm_reset_control_array_get_exclusive(&pdev->dev); - if (IS_ERR(rstc)) - return dev_err_probe(&pdev->dev, PTR_ERR(rstc), - "failed to get reset lines\n"); - - vpu_clk = devm_clk_get(&pdev->dev, "vpu"); - if (IS_ERR(vpu_clk)) { - dev_err(&pdev->dev, "vpu clock request failed\n"); - return PTR_ERR(vpu_clk); - } - - vapb_clk = devm_clk_get(&pdev->dev, "vapb"); - if (IS_ERR(vapb_clk)) { - dev_err(&pdev->dev, "vapb clock request failed\n"); - return PTR_ERR(vapb_clk); - } - - vpu_pd->regmap_ao = regmap_ao; - vpu_pd->regmap_hhi = regmap_hhi; - vpu_pd->rstc = rstc; - vpu_pd->vpu_clk = vpu_clk; - vpu_pd->vapb_clk = vapb_clk; - - platform_set_drvdata(pdev, vpu_pd); - - powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); - - /* If already powered, sync the clock states */ - if (!powered_off) { - ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); - if (ret) - return ret; - } - - vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON; - pm_genpd_init(&vpu_pd->genpd, NULL, powered_off); - - return of_genpd_add_provider_simple(pdev->dev.of_node, - &vpu_pd->genpd); -} - -static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) -{ - struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev); - bool powered_off; - - powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); - if (!powered_off) - vpu_pd->genpd.power_off(&vpu_pd->genpd); -} - -static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { - { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, - { - .compatible = "amlogic,meson-g12a-pwrc-vpu", - .data = &vpu_hdmi_pd_g12a - }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table); - -static struct platform_driver meson_gx_pwrc_vpu_driver = { - .probe = meson_gx_pwrc_vpu_probe, - .shutdown = meson_gx_pwrc_vpu_shutdown, - .driver = { - .name = "meson_gx_pwrc_vpu", - .of_match_table = meson_gx_pwrc_vpu_match_table, - }, -}; -module_platform_driver(meson_gx_pwrc_vpu_driver); -MODULE_DESCRIPTION("Amlogic Meson GX Power Domains driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pmdomain/apple/pmgr-pwrstate.c b/drivers/pmdomain/apple/pmgr-pwrstate.c index d62a776c89a1..9467235110f4 100644 --- a/drivers/pmdomain/apple/pmgr-pwrstate.c +++ b/drivers/pmdomain/apple/pmgr-pwrstate.c @@ -177,7 +177,7 @@ static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned return !!(reg & APPLE_PMGR_RESET); } -const struct reset_control_ops apple_pmgr_reset_ops = { +static const struct reset_control_ops apple_pmgr_reset_ops = { .assert = apple_pmgr_reset_assert, .deassert = apple_pmgr_reset_deassert, .reset = apple_pmgr_reset_reset, diff --git a/drivers/pmdomain/bcm/raspberrypi-power.c b/drivers/pmdomain/bcm/raspberrypi-power.c index 06196ebfe03b..b87ea7adb7be 100644 --- a/drivers/pmdomain/bcm/raspberrypi-power.c +++ b/drivers/pmdomain/bcm/raspberrypi-power.c @@ -41,40 +41,46 @@ struct rpi_power_domains { */ struct rpi_power_domain_packet { u32 domain; - u32 on; + u32 state; }; /* * Asks the firmware to enable or disable power on a specific power * domain. */ -static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on) +static int rpi_firmware_set_power(struct generic_pm_domain *domain, bool on) { + struct rpi_power_domain *rpi_domain = + container_of(domain, struct rpi_power_domain, base); + bool old_interface = rpi_domain->old_interface; struct rpi_power_domain_packet packet; + int ret; packet.domain = rpi_domain->domain; - packet.on = on; - return rpi_firmware_property(rpi_domain->fw, - rpi_domain->old_interface ? - RPI_FIRMWARE_SET_POWER_STATE : - RPI_FIRMWARE_SET_DOMAIN_STATE, - &packet, sizeof(packet)); + packet.state = on; + + ret = rpi_firmware_property(rpi_domain->fw, old_interface ? + RPI_FIRMWARE_SET_POWER_STATE : + RPI_FIRMWARE_SET_DOMAIN_STATE, + &packet, sizeof(packet)); + if (ret) + dev_err(&domain->dev, "Failed to set %s to %u (%d)\n", + old_interface ? "power" : "domain", on, ret); + else + dev_dbg(&domain->dev, "Set %s to %u\n", + old_interface ? "power" : "domain", on); + + return ret; } static int rpi_domain_off(struct generic_pm_domain *domain) { - struct rpi_power_domain *rpi_domain = - container_of(domain, struct rpi_power_domain, base); - - return rpi_firmware_set_power(rpi_domain, false); + return rpi_firmware_set_power(domain, false); } static int rpi_domain_on(struct generic_pm_domain *domain) { - struct rpi_power_domain *rpi_domain = - container_of(domain, struct rpi_power_domain, base); - - return rpi_firmware_set_power(rpi_domain, true); + return rpi_firmware_set_power(domain, true); } static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains, @@ -85,6 +91,7 @@ static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains, dom->fw = rpi_domains->fw; dom->base.name = name; + dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP; dom->base.power_on = rpi_domain_on; dom->base.power_off = rpi_domain_off; @@ -142,13 +149,13 @@ rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains) int ret; packet.domain = RPI_POWER_DOMAIN_ARM; - packet.on = ~0; + packet.state = ~0; ret = rpi_firmware_property(rpi_domains->fw, RPI_FIRMWARE_GET_DOMAIN_STATE, &packet, sizeof(packet)); - return ret == 0 && packet.on != ~0; + return ret == 0 && packet.state != ~0; } static int rpi_power_probe(struct platform_device *pdev) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 7a61aa88c061..2731b285e017 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -117,6 +117,48 @@ static const struct genpd_lock_ops genpd_spin_ops = { .unlock = genpd_unlock_spin, }; +static void genpd_lock_raw_spin(struct generic_pm_domain *genpd) + __acquires(&genpd->raw_slock) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&genpd->raw_slock, flags); + genpd->raw_lock_flags = flags; +} + +static void genpd_lock_nested_raw_spin(struct generic_pm_domain *genpd, + int depth) + __acquires(&genpd->raw_slock) +{ + unsigned long flags; + + raw_spin_lock_irqsave_nested(&genpd->raw_slock, flags, depth); + genpd->raw_lock_flags = flags; +} + +static int genpd_lock_interruptible_raw_spin(struct generic_pm_domain *genpd) + __acquires(&genpd->raw_slock) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&genpd->raw_slock, flags); + genpd->raw_lock_flags = flags; + return 0; +} + +static void genpd_unlock_raw_spin(struct generic_pm_domain *genpd) + __releases(&genpd->raw_slock) +{ + raw_spin_unlock_irqrestore(&genpd->raw_slock, genpd->raw_lock_flags); +} + +static const struct genpd_lock_ops genpd_raw_spin_ops = { + .lock = genpd_lock_raw_spin, + .lock_nested = genpd_lock_nested_raw_spin, + .lock_interruptible = genpd_lock_interruptible_raw_spin, + .unlock = genpd_unlock_raw_spin, +}; + #define genpd_lock(p) p->lock_ops->lock(p) #define genpd_lock_nested(p, d) p->lock_ops->lock_nested(p, d) #define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p) @@ -1758,7 +1800,6 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, genpd_lock(genpd); genpd_set_cpumask(genpd, gpd_data->cpu); - dev_pm_domain_set(dev, &genpd->domain); genpd->device_count++; if (gd) @@ -1767,6 +1808,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); genpd_unlock(genpd); + dev_pm_domain_set(dev, &genpd->domain); out: if (ret) genpd_free_dev_data(dev, gpd_data); @@ -1823,12 +1865,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, genpd->gd->max_off_time_changed = true; genpd_clear_cpumask(genpd, gpd_data->cpu); - dev_pm_domain_set(dev, NULL); list_del_init(&pdd->list_node); genpd_unlock(genpd); + dev_pm_domain_set(dev, NULL); + if (genpd->detach_dev) genpd->detach_dev(genpd, dev); @@ -2143,7 +2186,10 @@ static void genpd_free_data(struct generic_pm_domain *genpd) static void genpd_lock_init(struct generic_pm_domain *genpd) { - if (genpd_is_irq_safe(genpd)) { + if (genpd_is_cpu_domain(genpd)) { + raw_spin_lock_init(&genpd->raw_slock); + genpd->lock_ops = &genpd_raw_spin_ops; + } else if (genpd_is_irq_safe(genpd)) { spin_lock_init(&genpd->slock); genpd->lock_ops = &genpd_spin_ops; } else { @@ -3209,7 +3255,6 @@ static int genpd_summary_one(struct seq_file *s, [GENPD_STATE_OFF] = "off" }; struct pm_domain_data *pm_data; - const char *kobj_path; struct gpd_link *link; char state[16]; int ret; @@ -3242,17 +3287,10 @@ static int genpd_summary_one(struct seq_file *s, } list_for_each_entry(pm_data, &genpd->dev_list, list_node) { - kobj_path = kobject_get_path(&pm_data->dev->kobj, - genpd_is_irq_safe(genpd) ? - GFP_ATOMIC : GFP_KERNEL); - if (kobj_path == NULL) - continue; - - seq_printf(s, "\n %-50s ", kobj_path); + seq_printf(s, "\n %-50s ", dev_name(pm_data->dev)); rtpm_status_str(s, pm_data->dev); perf_status_str(s, pm_data->dev); mode_status_str(s, pm_data->dev); - kfree(kobj_path); } seq_puts(s, "\n"); @@ -3421,23 +3459,14 @@ static int devices_show(struct seq_file *s, void *data) { struct generic_pm_domain *genpd = s->private; struct pm_domain_data *pm_data; - const char *kobj_path; int ret = 0; ret = genpd_lock_interruptible(genpd); if (ret) return -ERESTARTSYS; - list_for_each_entry(pm_data, &genpd->dev_list, list_node) { - kobj_path = kobject_get_path(&pm_data->dev->kobj, - genpd_is_irq_safe(genpd) ? - GFP_ATOMIC : GFP_KERNEL); - if (kobj_path == NULL) - continue; - - seq_printf(s, "%s\n", kobj_path); - kfree(kobj_path); - } + list_for_each_entry(pm_data, &genpd->dev_list, list_node) + seq_printf(s, "%s\n", dev_name(pm_data->dev)); genpd_unlock(genpd); return ret; diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c index 9b76b62869d0..64b4d7120d83 100644 --- a/drivers/pmdomain/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c @@ -33,6 +33,7 @@ #include <dt-bindings/power/rk3368-power.h> #include <dt-bindings/power/rk3399-power.h> #include <dt-bindings/power/rk3568-power.h> +#include <dt-bindings/power/rockchip,rk3576-power.h> #include <dt-bindings/power/rk3588-power.h> struct rockchip_domain_info { @@ -175,6 +176,9 @@ struct rockchip_pmu { #define DOMAIN_RK3568(name, pwr, req, wakeup) \ DOMAIN_M(name, pwr, pwr, req, req, req, wakeup) +#define DOMAIN_RK3576(name, p_offset, pwr, status, r_status, r_offset, req, idle, wakeup) \ + DOMAIN_M_O_R(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, wakeup) + /* * Dynamic Memory Controller may need to coordinate with us -- see * rockchip_pmu_block(). @@ -1106,6 +1110,28 @@ static const struct rockchip_domain_info rk3568_pm_domains[] = { [RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false), }; +static const struct rockchip_domain_info rk3576_pm_domains[] = { + [RK3576_PD_NPU] = DOMAIN_RK3576("npu", 0x0, BIT(0), BIT(0), 0, 0x0, 0, 0, false), + [RK3576_PD_NVM] = DOMAIN_RK3576("nvm", 0x0, BIT(6), 0, BIT(6), 0x4, BIT(2), BIT(18), false), + [RK3576_PD_SDGMAC] = DOMAIN_RK3576("sdgmac", 0x0, BIT(7), 0, BIT(7), 0x4, BIT(1), BIT(17), false), + [RK3576_PD_AUDIO] = DOMAIN_RK3576("audio", 0x0, BIT(8), 0, BIT(8), 0x4, BIT(0), BIT(16), false), + [RK3576_PD_PHP] = DOMAIN_RK3576("php", 0x0, BIT(9), 0, BIT(9), 0x0, BIT(15), BIT(15), false), + [RK3576_PD_SUBPHP] = DOMAIN_RK3576("subphp", 0x0, BIT(10), 0, BIT(10), 0x0, 0, 0, false), + [RK3576_PD_VOP] = DOMAIN_RK3576("vop", 0x0, BIT(11), 0, BIT(11), 0x0, 0x6000, 0x6000, false), + [RK3576_PD_VO1] = DOMAIN_RK3576("vo1", 0x0, BIT(14), 0, BIT(14), 0x0, BIT(12), BIT(12), false), + [RK3576_PD_VO0] = DOMAIN_RK3576("vo0", 0x0, BIT(15), 0, BIT(15), 0x0, BIT(11), BIT(11), false), + [RK3576_PD_USB] = DOMAIN_RK3576("usb", 0x4, BIT(0), 0, BIT(16), 0x0, BIT(10), BIT(10), true), + [RK3576_PD_VI] = DOMAIN_RK3576("vi", 0x4, BIT(1), 0, BIT(17), 0x0, BIT(9), BIT(9), false), + [RK3576_PD_VEPU0] = DOMAIN_RK3576("vepu0", 0x4, BIT(2), 0, BIT(18), 0x0, BIT(7), BIT(7), false), + [RK3576_PD_VEPU1] = DOMAIN_RK3576("vepu1", 0x4, BIT(3), 0, BIT(19), 0x0, BIT(8), BIT(8), false), + [RK3576_PD_VDEC] = DOMAIN_RK3576("vdec", 0x4, BIT(4), 0, BIT(20), 0x0, BIT(6), BIT(6), false), + [RK3576_PD_VPU] = DOMAIN_RK3576("vpu", 0x4, BIT(5), 0, BIT(21), 0x0, BIT(5), BIT(5), false), + [RK3576_PD_NPUTOP] = DOMAIN_RK3576("nputop", 0x4, BIT(6), 0, BIT(22), 0x0, 0x18, 0x18, false), + [RK3576_PD_NPU0] = DOMAIN_RK3576("npu0", 0x4, BIT(7), 0, BIT(23), 0x0, BIT(1), BIT(1), false), + [RK3576_PD_NPU1] = DOMAIN_RK3576("npu1", 0x4, BIT(8), 0, BIT(24), 0x0, BIT(2), BIT(2), false), + [RK3576_PD_GPU] = DOMAIN_RK3576("gpu", 0x4, BIT(9), 0, BIT(25), 0x0, BIT(0), BIT(0), false), +}; + static const struct rockchip_domain_info rk3588_pm_domains[] = { [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false), [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false), @@ -1284,6 +1310,21 @@ static const struct rockchip_pmu_info rk3568_pmu = { .domain_info = rk3568_pm_domains, }; +static const struct rockchip_pmu_info rk3576_pmu = { + .pwr_offset = 0x210, + .status_offset = 0x230, + .chain_status_offset = 0x248, + .mem_status_offset = 0x250, + .mem_pwr_offset = 0x300, + .req_offset = 0x110, + .idle_offset = 0x128, + .ack_offset = 0x120, + .repair_status_offset = 0x570, + + .num_domains = ARRAY_SIZE(rk3576_pm_domains), + .domain_info = rk3576_pm_domains, +}; + static const struct rockchip_pmu_info rk3588_pmu = { .pwr_offset = 0x14c, .status_offset = 0x180, @@ -1360,6 +1401,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { .data = (void *)&rk3568_pmu, }, { + .compatible = "rockchip,rk3576-power-controller", + .data = (void *)&rk3576_pmu, + }, + { .compatible = "rockchip,rk3588-power-controller", .data = (void *)&rk3588_pmu, }, diff --git a/include/dt-bindings/power/rockchip,rk3576-power.h b/include/dt-bindings/power/rockchip,rk3576-power.h new file mode 100644 index 000000000000..324a056aa851 --- /dev/null +++ b/include/dt-bindings/power/rockchip,rk3576-power.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +#ifndef __DT_BINDINGS_POWER_RK3576_POWER_H__ +#define __DT_BINDINGS_POWER_RK3576_POWER_H__ + +/* VD_NPU */ +#define RK3576_PD_NPU 0 +#define RK3576_PD_NPUTOP 1 +#define RK3576_PD_NPU0 2 +#define RK3576_PD_NPU1 3 + +/* VD_GPU */ +#define RK3576_PD_GPU 4 + +/* VD_LOGIC */ +#define RK3576_PD_NVM 5 +#define RK3576_PD_SDGMAC 6 +#define RK3576_PD_USB 7 +#define RK3576_PD_PHP 8 +#define RK3576_PD_SUBPHP 9 +#define RK3576_PD_AUDIO 10 +#define RK3576_PD_VEPU0 11 +#define RK3576_PD_VEPU1 12 +#define RK3576_PD_VPU 13 +#define RK3576_PD_VDEC 14 +#define RK3576_PD_VI 15 +#define RK3576_PD_VO0 16 +#define RK3576_PD_VO1 17 +#define RK3576_PD_VOP 18 + +#endif diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 858c8e7851fb..b637ec14025f 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -198,8 +198,11 @@ struct generic_pm_domain { spinlock_t slock; unsigned long lock_flags; }; + struct { + raw_spinlock_t raw_slock; + unsigned long raw_lock_flags; + }; }; - }; static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) @@ -473,6 +476,9 @@ struct device *dev_pm_domain_attach_by_name(struct device *dev, int dev_pm_domain_attach_list(struct device *dev, const struct dev_pm_domain_attach_data *data, struct dev_pm_domain_list **list); +int devm_pm_domain_attach_list(struct device *dev, + const struct dev_pm_domain_attach_data *data, + struct dev_pm_domain_list **list); void dev_pm_domain_detach(struct device *dev, bool power_off); void dev_pm_domain_detach_list(struct dev_pm_domain_list *list); int dev_pm_domain_start(struct device *dev); @@ -499,6 +505,14 @@ static inline int dev_pm_domain_attach_list(struct device *dev, { return 0; } + +static inline int devm_pm_domain_attach_list(struct device *dev, + const struct dev_pm_domain_attach_data *data, + struct dev_pm_domain_list **list) +{ + return 0; +} + static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} static inline void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) {} static inline int dev_pm_domain_start(struct device *dev) |