aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/power/rockchip,power-controller.yaml1
-rw-r--r--drivers/base/power/common.c45
-rw-r--r--drivers/cpuidle/cpuidle-psci-domain.c17
-rw-r--r--drivers/cpuidle/cpuidle-psci.c26
-rw-r--r--drivers/cpuidle/dt_idle_genpd.c14
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c5
-rw-r--r--drivers/pmdomain/amlogic/Kconfig11
-rw-r--r--drivers/pmdomain/amlogic/Makefile1
-rw-r--r--drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c380
-rw-r--r--drivers/pmdomain/apple/pmgr-pwrstate.c2
-rw-r--r--drivers/pmdomain/bcm/raspberrypi-power.c43
-rw-r--r--drivers/pmdomain/core.c75
-rw-r--r--drivers/pmdomain/rockchip/pm-domains.c45
-rw-r--r--include/dt-bindings/power/rockchip,rk3576-power.h30
-rw-r--r--include/linux/pm_domain.h16
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, &reg);
-
- 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)