Commit 200289db authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pmdomain-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm

Pull pmdomain updates from Ulf Hansson:
 "pmdomain core:
   - Add support for s2idle for CPU PM domains on PREEMPT_RT
   - Add device managed version of dev_pm_domain_attach|detach_list()
   - Improve layout of the debugfs summary table

  pmdomain providers:
   - amlogic: Remove obsolete vpu domain driver
   - bcm: raspberrypi: Add support for devices used as wakeup-sources
   - imx: Fixup clock handling for imx93 at driver remove
   - rockchip: Add gating support for RK3576
   - rockchip: Add support for RK3576 SoC
   - Some OF parsing simplifications
   - Some simplifications by using dev_err_probe() and guard()

  pmdomain consumers:
   - qcom/media/venus: Convert to the device managed APIs for PM domains

  cpuidle-psci:
   - Add support for s2idle/s2ram for the hierarchical topology on
     PREEMPT_RT
   - Some OF parsing simplifications"

* tag 'pmdomain-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (39 commits)
  pmdomain: core: Reduce debug summary table width
  pmdomain: core: Move mode_status_str()
  pmdomain: core: Fix "managed by" alignment in debug summary
  pmdomain: core: Harden inter-column space in debug summary
  pmdomain: rockchip: Add gating masks for rk3576
  pmdomain: rockchip: Add gating support
  pmdomain: rockchip: Simplify dropping OF node reference
  pmdomain: mediatek: make use of dev_err_cast_probe()
  pmdomain: imx93-pd: drop the context variable "init_off"
  pmdomain: imx93-pd: don't unprepare clocks on driver remove
  pmdomain: imx93-pd: replace dev_err() with dev_err_probe()
  pmdomain: qcom: rpmpd: Simplify locking with guard()
  pmdomain: qcom: rpmhpd: Simplify locking with guard()
  pmdomain: qcom: cpr: Simplify locking with guard()
  pmdomain: qcom: cpr: Simplify with dev_err_probe()
  pmdomain: imx: gpcv2: Simplify with scoped for each OF child loop
  pmdomain: imx: gpc: Simplify with scoped for each OF child loop
  pmdomain: rockchip: SimplUlf Hanssonify locking with guard()
  pmdomain: rockchip: Simplify with scoped for each OF child loop
  pmdomain: qcom-cpr: Use scope based of_node_put() to simplify code.
  ...
parents 2fe3c78a c6ccb691
...@@ -41,6 +41,7 @@ properties: ...@@ -41,6 +41,7 @@ properties:
- rockchip,rk3368-power-controller - rockchip,rk3368-power-controller
- rockchip,rk3399-power-controller - rockchip,rk3399-power-controller
- rockchip,rk3568-power-controller - rockchip,rk3568-power-controller
- rockchip,rk3576-power-controller
- rockchip,rk3588-power-controller - rockchip,rk3588-power-controller
- rockchip,rv1126-power-controller - rockchip,rv1126-power-controller
......
...@@ -276,6 +276,51 @@ int dev_pm_domain_attach_list(struct device *dev, ...@@ -276,6 +276,51 @@ int dev_pm_domain_attach_list(struct device *dev,
} }
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_list); 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_pm_domain_detach - Detach a device from its PM domain.
* @dev: Device to detach. * @dev: Device to detach.
......
...@@ -67,12 +67,16 @@ static int psci_pd_init(struct device_node *np, bool use_osi) ...@@ -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. * 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; 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; pd->flags |= GENPD_FLAG_ALWAYS_ON;
}
/* Use governor for CPU PM domains if it has some states to manage. */ /* Use governor for CPU PM domains if it has some states to manage. */
pd_gov = pd->states ? &pm_domain_cpu_gov : NULL; pd_gov = pd->states ? &pm_domain_cpu_gov : NULL;
...@@ -138,7 +142,6 @@ static const struct of_device_id psci_of_match[] = { ...@@ -138,7 +142,6 @@ static const struct of_device_id psci_of_match[] = {
static int psci_cpuidle_domain_probe(struct platform_device *pdev) static int psci_cpuidle_domain_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct device_node *node;
bool use_osi = psci_has_osi_support(); bool use_osi = psci_has_osi_support();
int ret = 0, pd_count = 0; int ret = 0, pd_count = 0;
...@@ -149,15 +152,13 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev) ...@@ -149,15 +152,13 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
* Parse child nodes for the "#power-domain-cells" property and * Parse child nodes for the "#power-domain-cells" property and
* initialize a genpd/genpd-of-provider pair when it's found. * 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")) if (!of_property_present(node, "#power-domain-cells"))
continue; continue;
ret = psci_pd_init(node, use_osi); ret = psci_pd_init(node, use_osi);
if (ret) { if (ret)
of_node_put(node);
goto exit; goto exit;
}
pd_count++; pd_count++;
} }
......
...@@ -37,6 +37,7 @@ struct psci_cpuidle_data { ...@@ -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_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data);
static DEFINE_PER_CPU(u32, domain_state); static DEFINE_PER_CPU(u32, domain_state);
static bool psci_cpuidle_use_syscore;
static bool psci_cpuidle_use_cpuhp; static bool psci_cpuidle_use_cpuhp;
void psci_set_domain_state(u32 state) void psci_set_domain_state(u32 state)
...@@ -166,6 +167,12 @@ static struct syscore_ops psci_idle_syscore_ops = { ...@@ -166,6 +167,12 @@ static struct syscore_ops psci_idle_syscore_ops = {
.resume = psci_idle_syscore_resume, .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) static void psci_idle_init_cpuhp(void)
{ {
int err; int err;
...@@ -173,8 +180,6 @@ static void psci_idle_init_cpuhp(void) ...@@ -173,8 +180,6 @@ static void psci_idle_init_cpuhp(void)
if (!psci_cpuidle_use_cpuhp) if (!psci_cpuidle_use_cpuhp)
return; return;
register_syscore_ops(&psci_idle_syscore_ops);
err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING, err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING,
"cpuidle/psci:online", "cpuidle/psci:online",
psci_idle_cpuhp_up, psci_idle_cpuhp_up,
...@@ -222,22 +227,23 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv, ...@@ -222,22 +227,23 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv,
if (!psci_has_osi_support()) if (!psci_has_osi_support())
return 0; return 0;
if (IS_ENABLED(CONFIG_PREEMPT_RT))
return 0;
data->dev = dt_idle_attach_cpu(cpu, "psci"); data->dev = dt_idle_attach_cpu(cpu, "psci");
if (IS_ERR_OR_NULL(data->dev)) if (IS_ERR_OR_NULL(data->dev))
return PTR_ERR_OR_ZERO(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 * 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 * 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; 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; return 0;
} }
...@@ -313,6 +319,7 @@ static void psci_cpu_deinit_idle(int cpu) ...@@ -313,6 +319,7 @@ static void psci_cpu_deinit_idle(int cpu)
struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu); struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu);
dt_idle_detach_cpu(data->dev); dt_idle_detach_cpu(data->dev);
psci_cpuidle_use_syscore = false;
psci_cpuidle_use_cpuhp = false; psci_cpuidle_use_cpuhp = false;
} }
...@@ -409,6 +416,7 @@ static int psci_cpuidle_probe(struct platform_device *pdev) ...@@ -409,6 +416,7 @@ static int psci_cpuidle_probe(struct platform_device *pdev)
goto out_fail; goto out_fail;
} }
psci_idle_init_syscore();
psci_idle_init_cpuhp(); psci_idle_init_cpuhp();
return 0; return 0;
......
...@@ -130,11 +130,10 @@ struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np, ...@@ -130,11 +130,10 @@ struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np,
int dt_idle_pd_init_topology(struct device_node *np) int dt_idle_pd_init_topology(struct device_node *np)
{ {
struct device_node *node;
struct of_phandle_args child, parent; struct of_phandle_args child, parent;
int ret; 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", if (of_parse_phandle_with_args(node, "power-domains",
"#power-domain-cells", 0, &parent)) "#power-domain-cells", 0, &parent))
continue; continue;
...@@ -143,10 +142,8 @@ int dt_idle_pd_init_topology(struct device_node *np) ...@@ -143,10 +142,8 @@ int dt_idle_pd_init_topology(struct device_node *np)
child.args_count = 0; child.args_count = 0;
ret = of_genpd_add_subdomain(&parent, &child); ret = of_genpd_add_subdomain(&parent, &child);
of_node_put(parent.np); of_node_put(parent.np);
if (ret) { if (ret)
of_node_put(node);
return ret; return ret;
}
} }
return 0; return 0;
...@@ -154,11 +151,10 @@ int dt_idle_pd_init_topology(struct device_node *np) ...@@ -154,11 +151,10 @@ int dt_idle_pd_init_topology(struct device_node *np)
int dt_idle_pd_remove_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; struct of_phandle_args child, parent;
int ret; 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", if (of_parse_phandle_with_args(node, "power-domains",
"#power-domain-cells", 0, &parent)) "#power-domain-cells", 0, &parent))
continue; continue;
...@@ -167,10 +163,8 @@ int dt_idle_pd_remove_topology(struct device_node *np) ...@@ -167,10 +163,8 @@ int dt_idle_pd_remove_topology(struct device_node *np)
child.args_count = 0; child.args_count = 0;
ret = of_genpd_remove_subdomain(&parent, &child); ret = of_genpd_remove_subdomain(&parent, &child);
of_node_put(parent.np); of_node_put(parent.np);
if (ret) { if (ret)
of_node_put(node);
return ret; return ret;
}
} }
return 0; return 0;
......
...@@ -876,7 +876,7 @@ static int vcodec_domains_get(struct venus_core *core) ...@@ -876,7 +876,7 @@ static int vcodec_domains_get(struct venus_core *core)
if (!res->vcodec_pmdomains_num) if (!res->vcodec_pmdomains_num)
goto skip_pmdomains; 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) if (ret < 0)
return ret; return ret;
...@@ -902,14 +902,11 @@ static int vcodec_domains_get(struct venus_core *core) ...@@ -902,14 +902,11 @@ static int vcodec_domains_get(struct venus_core *core)
return 0; return 0;
opp_attach_err: opp_attach_err:
dev_pm_domain_detach_list(core->pmdomains);
return ret; return ret;
} }
static void vcodec_domains_put(struct venus_core *core) static void vcodec_domains_put(struct venus_core *core)
{ {
dev_pm_domain_detach_list(core->pmdomains);
if (!core->has_opp_table) if (!core->has_opp_table)
return; return;
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
menu "Amlogic PM Domains" 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 config MESON_EE_PM_DOMAINS
tristate "Amlogic Meson Everything-Else Power Domains driver" tristate "Amlogic Meson Everything-Else Power Domains driver"
depends on ARCH_MESON || COMPILE_TEST depends on ARCH_MESON || COMPILE_TEST
......
# SPDX-License-Identifier: GPL-2.0-only # 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_EE_PM_DOMAINS) += meson-ee-pwrc.o
obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o
/*
* Copyright (c) 2017 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* 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");
...@@ -177,7 +177,7 @@ static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned ...@@ -177,7 +177,7 @@ static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned
return !!(reg & APPLE_PMGR_RESET); 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, .assert = apple_pmgr_reset_assert,
.deassert = apple_pmgr_reset_deassert, .deassert = apple_pmgr_reset_deassert,
.reset = apple_pmgr_reset_reset, .reset = apple_pmgr_reset_reset,
......
...@@ -41,40 +41,46 @@ struct rpi_power_domains { ...@@ -41,40 +41,46 @@ struct rpi_power_domains {
*/ */
struct rpi_power_domain_packet { struct rpi_power_domain_packet {
u32 domain; u32 domain;
u32 on; u32 state;
}; };
/* /*
* Asks the firmware to enable or disable power on a specific power * Asks the firmware to enable or disable power on a specific power
* domain. * 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; struct rpi_power_domain_packet packet;
int ret;
packet.domain = rpi_domain->domain; packet.domain = rpi_domain->domain;
packet.on = on; packet.state = on;
return rpi_firmware_property(rpi_domain->fw,
rpi_domain->old_interface ? ret = rpi_firmware_property(rpi_domain->fw, old_interface ?
RPI_FIRMWARE_SET_POWER_STATE : RPI_FIRMWARE_SET_POWER_STATE :
RPI_FIRMWARE_SET_DOMAIN_STATE, RPI_FIRMWARE_SET_DOMAIN_STATE,
&packet, sizeof(packet)); &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) static int rpi_domain_off(struct generic_pm_domain *domain)
{ {
struct rpi_power_domain *rpi_domain = return rpi_firmware_set_power(domain, false);
container_of(domain, struct rpi_power_domain, base);
return rpi_firmware_set_power(rpi_domain, false);
} }
static int rpi_domain_on(struct generic_pm_domain *domain) static int rpi_domain_on(struct generic_pm_domain *domain)
{ {
struct rpi_power_domain *rpi_domain = return rpi_firmware_set_power(domain, true);
container_of(domain, struct rpi_power_domain, base);
return rpi_firmware_set_power(rpi_domain, true);
} }
static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains, 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, ...@@ -85,6 +91,7 @@ static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
dom->fw = rpi_domains->fw; dom->fw = rpi_domains->fw;
dom->base.name = name; dom->base.name = name;
dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP;
dom->base.power_on = rpi_domain_on; dom->base.power_on = rpi_domain_on;
dom->base.power_off = rpi_domain_off; dom->base.power_off = rpi_domain_off;
...@@ -142,13 +149,13 @@ rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains) ...@@ -142,13 +149,13 @@ rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
int ret; int ret;
packet.domain = RPI_POWER_DOMAIN_ARM; packet.domain = RPI_POWER_DOMAIN_ARM;
packet.on = ~0; packet.state = ~0;
ret = rpi_firmware_property(rpi_domains->fw, ret = rpi_firmware_property(rpi_domains->fw,
RPI_FIRMWARE_GET_DOMAIN_STATE, RPI_FIRMWARE_GET_DOMAIN_STATE,
&packet, sizeof(packet)); &packet, sizeof(packet));
return ret == 0 && packet.on != ~0; return ret == 0 && packet.state != ~0;
} }
static int rpi_power_probe(struct platform_device *pdev) static int rpi_power_probe(struct platform_device *pdev)
......
...@@ -117,6 +117,48 @@ static const struct genpd_lock_ops genpd_spin_ops = { ...@@ -117,6 +117,48 @@ static const struct genpd_lock_ops genpd_spin_ops = {
.unlock = genpd_unlock_spin, .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(p) p->lock_ops->lock(p)
#define genpd_lock_nested(p, d) p->lock_ops->lock_nested(p, d) #define genpd_lock_nested(p, d) p->lock_ops->lock_nested(p, d)
#define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p) #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, ...@@ -1758,7 +1800,6 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
genpd_lock(genpd); genpd_lock(genpd);
genpd_set_cpumask(genpd, gpd_data->cpu); genpd_set_cpumask(genpd, gpd_data->cpu);
dev_pm_domain_set(dev, &genpd->domain);
genpd->device_count++; genpd->device_count++;
if (gd) if (gd)
...@@ -1767,6 +1808,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, ...@@ -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); list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
genpd_unlock(genpd); genpd_unlock(genpd);
dev_pm_domain_set(dev, &genpd->domain);
out: out:
if (ret) if (ret)
genpd_free_dev_data(dev, gpd_data); genpd_free_dev_data(dev, gpd_data);
...@@ -1823,12 +1865,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, ...@@ -1823,12 +1865,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
genpd->gd->max_off_time_changed = true; genpd->gd->max_off_time_changed = true;
genpd_clear_cpumask(genpd, gpd_data->cpu); genpd_clear_cpumask(genpd, gpd_data->cpu);
dev_pm_domain_set(dev, NULL);
list_del_init(&pdd->list_node); list_del_init(&pdd->list_node);
genpd_unlock(genpd); genpd_unlock(genpd);
dev_pm_domain_set(dev, NULL);
if (genpd->detach_dev) if (genpd->detach_dev)
genpd->detach_dev(genpd, dev); genpd->detach_dev(genpd, dev);
...@@ -2143,7 +2186,10 @@ static void genpd_free_data(struct generic_pm_domain *genpd) ...@@ -2143,7 +2186,10 @@ static void genpd_free_data(struct generic_pm_domain *genpd)
static void genpd_lock_init(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); spin_lock_init(&genpd->slock);
genpd->lock_ops = &genpd_spin_ops; genpd->lock_ops = &genpd_spin_ops;
} else { } else {
...@@ -3181,24 +3227,25 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev) ...@@ -3181,24 +3227,25 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
else else
WARN_ON(1); WARN_ON(1);
seq_printf(s, "%-25s ", p); seq_printf(s, "%-26s ", p);
} }
static void mode_status_str(struct seq_file *s, struct device *dev) static void perf_status_str(struct seq_file *s, struct device *dev)
{ {
struct generic_pm_domain_data *gpd_data; struct generic_pm_domain_data *gpd_data;
gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
seq_printf(s, "%20s", gpd_data->hw_mode ? "HW" : "SW"); seq_printf(s, "%-10u ", gpd_data->performance_state);
} }
static void perf_status_str(struct seq_file *s, struct device *dev) static void mode_status_str(struct seq_file *s, struct device *dev)
{ {
struct generic_pm_domain_data *gpd_data; struct generic_pm_domain_data *gpd_data;
gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
seq_put_decimal_ull(s, "", gpd_data->performance_state);
seq_printf(s, "%2s", gpd_data->hw_mode ? "HW" : "SW");
} }
static int genpd_summary_one(struct seq_file *s, static int genpd_summary_one(struct seq_file *s,
...@@ -3209,7 +3256,6 @@ static int genpd_summary_one(struct seq_file *s, ...@@ -3209,7 +3256,6 @@ static int genpd_summary_one(struct seq_file *s,
[GENPD_STATE_OFF] = "off" [GENPD_STATE_OFF] = "off"
}; };
struct pm_domain_data *pm_data; struct pm_domain_data *pm_data;
const char *kobj_path;
struct gpd_link *link; struct gpd_link *link;
char state[16]; char state[16];
int ret; int ret;
...@@ -3226,7 +3272,7 @@ static int genpd_summary_one(struct seq_file *s, ...@@ -3226,7 +3272,7 @@ static int genpd_summary_one(struct seq_file *s,
else else
snprintf(state, sizeof(state), "%s", snprintf(state, sizeof(state), "%s",
status_lookup[genpd->status]); status_lookup[genpd->status]);
seq_printf(s, "%-30s %-50s %u", genpd->name, state, genpd->performance_state); seq_printf(s, "%-30s %-30s %u", genpd->name, state, genpd->performance_state);
/* /*
* Modifications on the list require holding locks on both * Modifications on the list require holding locks on both
...@@ -3242,17 +3288,10 @@ static int genpd_summary_one(struct seq_file *s, ...@@ -3242,17 +3288,10 @@ static int genpd_summary_one(struct seq_file *s,
} }
list_for_each_entry(pm_data, &genpd->dev_list, list_node) { list_for_each_entry(pm_data, &genpd->dev_list, list_node) {
kobj_path = kobject_get_path(&pm_data->dev->kobj, seq_printf(s, "\n %-30s ", dev_name(pm_data->dev));
genpd_is_irq_safe(genpd) ?
GFP_ATOMIC : GFP_KERNEL);
if (kobj_path == NULL)
continue;
seq_printf(s, "\n %-50s ", kobj_path);
rtpm_status_str(s, pm_data->dev); rtpm_status_str(s, pm_data->dev);
perf_status_str(s, pm_data->dev); perf_status_str(s, pm_data->dev);
mode_status_str(s, pm_data->dev); mode_status_str(s, pm_data->dev);
kfree(kobj_path);
} }
seq_puts(s, "\n"); seq_puts(s, "\n");
...@@ -3267,9 +3306,9 @@ static int summary_show(struct seq_file *s, void *data) ...@@ -3267,9 +3306,9 @@ static int summary_show(struct seq_file *s, void *data)
struct generic_pm_domain *genpd; struct generic_pm_domain *genpd;
int ret = 0; int ret = 0;
seq_puts(s, "domain status children performance\n"); seq_puts(s, "domain status children performance\n");
seq_puts(s, " /device runtime status managed by\n"); seq_puts(s, " /device runtime status managed by\n");
seq_puts(s, "------------------------------------------------------------------------------------------------------------\n"); seq_puts(s, "------------------------------------------------------------------------------\n");
ret = mutex_lock_interruptible(&gpd_list_lock); ret = mutex_lock_interruptible(&gpd_list_lock);
if (ret) if (ret)
...@@ -3421,23 +3460,14 @@ static int devices_show(struct seq_file *s, void *data) ...@@ -3421,23 +3460,14 @@ static int devices_show(struct seq_file *s, void *data)
{ {
struct generic_pm_domain *genpd = s->private; struct generic_pm_domain *genpd = s->private;
struct pm_domain_data *pm_data; struct pm_domain_data *pm_data;
const char *kobj_path;
int ret = 0; int ret = 0;
ret = genpd_lock_interruptible(genpd); ret = genpd_lock_interruptible(genpd);
if (ret) if (ret)
return -ERESTARTSYS; return -ERESTARTSYS;
list_for_each_entry(pm_data, &genpd->dev_list, list_node) { list_for_each_entry(pm_data, &genpd->dev_list, list_node)
kobj_path = kobject_get_path(&pm_data->dev->kobj, seq_printf(s, "%s\n", dev_name(pm_data->dev));
genpd_is_irq_safe(genpd) ?
GFP_ATOMIC : GFP_KERNEL);
if (kobj_path == NULL)
continue;
seq_printf(s, "%s\n", kobj_path);
kfree(kobj_path);
}
genpd_unlock(genpd); genpd_unlock(genpd);
return ret; return ret;
......
...@@ -455,7 +455,6 @@ static int imx_gpc_probe(struct platform_device *pdev) ...@@ -455,7 +455,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
} else { } else {
struct imx_pm_domain *domain; struct imx_pm_domain *domain;
struct platform_device *pd_pdev; struct platform_device *pd_pdev;
struct device_node *np;
struct clk *ipg_clk; struct clk *ipg_clk;
unsigned int ipg_rate_mhz; unsigned int ipg_rate_mhz;
int domain_index; int domain_index;
...@@ -465,28 +464,24 @@ static int imx_gpc_probe(struct platform_device *pdev) ...@@ -465,28 +464,24 @@ static int imx_gpc_probe(struct platform_device *pdev)
return PTR_ERR(ipg_clk); return PTR_ERR(ipg_clk);
ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000; ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
for_each_child_of_node(pgc_node, np) { for_each_child_of_node_scoped(pgc_node, np) {
ret = of_property_read_u32(np, "reg", &domain_index); ret = of_property_read_u32(np, "reg", &domain_index);
if (ret) { if (ret)
of_node_put(np);
return ret; return ret;
}
if (domain_index >= of_id_data->num_domains) if (domain_index >= of_id_data->num_domains)
continue; continue;
pd_pdev = platform_device_alloc("imx-pgc-power-domain", pd_pdev = platform_device_alloc("imx-pgc-power-domain",
domain_index); domain_index);
if (!pd_pdev) { if (!pd_pdev)
of_node_put(np);
return -ENOMEM; return -ENOMEM;
}
ret = platform_device_add_data(pd_pdev, ret = platform_device_add_data(pd_pdev,
&imx_gpc_domains[domain_index], &imx_gpc_domains[domain_index],
sizeof(imx_gpc_domains[domain_index])); sizeof(imx_gpc_domains[domain_index]));
if (ret) { if (ret) {
platform_device_put(pd_pdev); platform_device_put(pd_pdev);
of_node_put(np);
return ret; return ret;
} }
domain = pd_pdev->dev.platform_data; domain = pd_pdev->dev.platform_data;
...@@ -500,7 +495,6 @@ static int imx_gpc_probe(struct platform_device *pdev) ...@@ -500,7 +495,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
ret = platform_device_add(pd_pdev); ret = platform_device_add(pd_pdev);
if (ret) { if (ret) {
platform_device_put(pd_pdev); platform_device_put(pd_pdev);
of_node_put(np);
return ret; return ret;
} }
} }
......
...@@ -1458,7 +1458,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev) ...@@ -1458,7 +1458,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
.max_register = SZ_4K, .max_register = SZ_4K,
}; };
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *pgc_np, *np; struct device_node *pgc_np;
struct regmap *regmap; struct regmap *regmap;
void __iomem *base; void __iomem *base;
int ret; int ret;
...@@ -1480,7 +1480,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev) ...@@ -1480,7 +1480,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
return ret; return ret;
} }
for_each_child_of_node(pgc_np, np) { for_each_child_of_node_scoped(pgc_np, np) {
struct platform_device *pd_pdev; struct platform_device *pd_pdev;
struct imx_pgc_domain *domain; struct imx_pgc_domain *domain;
u32 domain_index; u32 domain_index;
...@@ -1491,7 +1491,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) ...@@ -1491,7 +1491,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
ret = of_property_read_u32(np, "reg", &domain_index); ret = of_property_read_u32(np, "reg", &domain_index);
if (ret) { if (ret) {
dev_err(dev, "Failed to read 'reg' property\n"); dev_err(dev, "Failed to read 'reg' property\n");
of_node_put(np);
return ret; return ret;
} }
...@@ -1506,7 +1505,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) ...@@ -1506,7 +1505,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
domain_index); domain_index);
if (!pd_pdev) { if (!pd_pdev) {
dev_err(dev, "Failed to allocate platform device\n"); dev_err(dev, "Failed to allocate platform device\n");
of_node_put(np);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1515,7 +1513,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) ...@@ -1515,7 +1513,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
sizeof(domain_data->domains[domain_index])); sizeof(domain_data->domains[domain_index]));
if (ret) { if (ret) {
platform_device_put(pd_pdev); platform_device_put(pd_pdev);
of_node_put(np);
return ret; return ret;
} }
...@@ -1532,7 +1529,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) ...@@ -1532,7 +1529,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
ret = platform_device_add(pd_pdev); ret = platform_device_add(pd_pdev);
if (ret) { if (ret) {
platform_device_put(pd_pdev); platform_device_put(pd_pdev);
of_node_put(np);
return ret; return ret;
} }
} }
......
...@@ -28,7 +28,6 @@ struct imx93_power_domain { ...@@ -28,7 +28,6 @@ struct imx93_power_domain {
void __iomem *addr; void __iomem *addr;
struct clk_bulk_data *clks; struct clk_bulk_data *clks;
int num_clks; int num_clks;
bool init_off;
}; };
#define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd) #define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd)
...@@ -90,9 +89,6 @@ static void imx93_pd_remove(struct platform_device *pdev) ...@@ -90,9 +89,6 @@ static void imx93_pd_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
if (!domain->init_off)
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
of_genpd_del_provider(np); of_genpd_del_provider(np);
pm_genpd_remove(&domain->genpd); pm_genpd_remove(&domain->genpd);
} }
...@@ -102,6 +98,7 @@ static int imx93_pd_probe(struct platform_device *pdev) ...@@ -102,6 +98,7 @@ static int imx93_pd_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct imx93_power_domain *domain; struct imx93_power_domain *domain;
bool init_off;
int ret; int ret;
domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
...@@ -121,18 +118,17 @@ static int imx93_pd_probe(struct platform_device *pdev) ...@@ -121,18 +118,17 @@ static int imx93_pd_probe(struct platform_device *pdev)
domain->genpd.power_on = imx93_pd_on; domain->genpd.power_on = imx93_pd_on;
domain->dev = dev; domain->dev = dev;
domain->init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK; init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK;
/* Just to sync the status of hardware */ /* Just to sync the status of hardware */
if (!domain->init_off) { if (!init_off) {
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
if (ret) { if (ret)
dev_err(domain->dev, "failed to enable clocks for domain: %s\n", return dev_err_probe(domain->dev, ret,
domain->genpd.name); "failed to enable clocks for domain: %s\n",
return ret; domain->genpd.name);
}
} }
ret = pm_genpd_init(&domain->genpd, NULL, domain->init_off); ret = pm_genpd_init(&domain->genpd, NULL, init_off);
if (ret) if (ret)
goto err_clk_unprepare; goto err_clk_unprepare;
...@@ -148,7 +144,7 @@ static int imx93_pd_probe(struct platform_device *pdev) ...@@ -148,7 +144,7 @@ static int imx93_pd_probe(struct platform_device *pdev)
pm_genpd_remove(&domain->genpd); pm_genpd_remove(&domain->genpd);
err_clk_unprepare: err_clk_unprepare:
if (!domain->init_off) if (!init_off)
clk_bulk_disable_unprepare(domain->num_clks, domain->clks); clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
return ret; return ret;
......
...@@ -398,12 +398,10 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no ...@@ -398,12 +398,10 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
scpsys->dev->of_node = node; scpsys->dev->of_node = node;
pd->supply = devm_regulator_get(scpsys->dev, "domain"); pd->supply = devm_regulator_get(scpsys->dev, "domain");
scpsys->dev->of_node = root_node; scpsys->dev->of_node = root_node;
if (IS_ERR(pd->supply)) { if (IS_ERR(pd->supply))
dev_err_probe(scpsys->dev, PTR_ERR(pd->supply), return dev_err_cast_probe(scpsys->dev, pd->supply,
"%pOF: failed to get power supply.\n", "%pOF: failed to get power supply.\n",
node); node);
return ERR_CAST(pd->supply);
}
} }
pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg"); pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg");
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (c) 2019, Linaro Limited * Copyright (c) 2019, Linaro Limited
*/ */
#include <linux/cleanup.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -747,9 +748,9 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain, ...@@ -747,9 +748,9 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain,
struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd); struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd);
struct corner *corner, *end; struct corner *corner, *end;
enum voltage_change_dir dir; enum voltage_change_dir dir;
int ret = 0, new_uV; int ret, new_uV;
mutex_lock(&drv->lock); guard(mutex)(&drv->lock);
dev_dbg(drv->dev, "%s: setting perf state: %u (prev state: %u)\n", dev_dbg(drv->dev, "%s: setting perf state: %u (prev state: %u)\n",
__func__, state, cpr_get_cur_perf_state(drv)); __func__, state, cpr_get_cur_perf_state(drv));
...@@ -760,10 +761,8 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain, ...@@ -760,10 +761,8 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain,
*/ */
corner = drv->corners + state - 1; corner = drv->corners + state - 1;
end = &drv->corners[drv->num_corners - 1]; end = &drv->corners[drv->num_corners - 1];
if (corner > end || corner < drv->corners) { if (corner > end || corner < drv->corners)
ret = -EINVAL; return -EINVAL;
goto unlock;
}
/* Determine direction */ /* Determine direction */
if (drv->corner > corner) if (drv->corner > corner)
...@@ -783,7 +782,7 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain, ...@@ -783,7 +782,7 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain,
ret = cpr_scale_voltage(drv, corner, new_uV, dir); ret = cpr_scale_voltage(drv, corner, new_uV, dir);
if (ret) if (ret)
goto unlock; return ret;
if (cpr_is_allowed(drv)) { if (cpr_is_allowed(drv)) {
cpr_irq_clr(drv); cpr_irq_clr(drv);
...@@ -794,10 +793,7 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain, ...@@ -794,10 +793,7 @@ static int cpr_set_performance_state(struct generic_pm_domain *domain,
drv->corner = corner; drv->corner = corner;
unlock: return 0;
mutex_unlock(&drv->lock);
return ret;
} }
static int static int
...@@ -1040,36 +1036,30 @@ static unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp) ...@@ -1040,36 +1036,30 @@ static unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp)
static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref, static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
struct device *cpu_dev) struct device *cpu_dev)
{ {
u64 rate = 0; struct device_node *ref_np __free(device_node) = NULL;
struct device_node *ref_np; struct device_node *desc_np __free(device_node) =
struct device_node *desc_np; dev_pm_opp_of_get_opp_desc_node(cpu_dev);
struct device_node *child_np = NULL;
struct device_node *child_req_np = NULL;
desc_np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
if (!desc_np) if (!desc_np)
return 0; return 0;
ref_np = dev_pm_opp_get_of_node(ref); ref_np = dev_pm_opp_get_of_node(ref);
if (!ref_np) if (!ref_np)
goto out_ref; return 0;
do { for_each_available_child_of_node_scoped(desc_np, child_np) {
of_node_put(child_req_np); struct device_node *child_req_np __free(device_node) =
child_np = of_get_next_available_child(desc_np, child_np); of_parse_phandle(child_np, "required-opps", 0);
child_req_np = of_parse_phandle(child_np, "required-opps", 0);
} while (child_np && child_req_np != ref_np);
if (child_np && child_req_np == ref_np) if (child_req_np == ref_np) {
of_property_read_u64(child_np, "opp-hz", &rate); u64 rate;
of_node_put(child_req_np); of_property_read_u64(child_np, "opp-hz", &rate);
of_node_put(child_np); return (unsigned long) rate;
of_node_put(ref_np); }
out_ref: }
of_node_put(desc_np);
return (unsigned long) rate; return 0;
} }
static int cpr_corner_init(struct cpr_drv *drv) static int cpr_corner_init(struct cpr_drv *drv)
...@@ -1443,9 +1433,9 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain, ...@@ -1443,9 +1433,9 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
{ {
struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd); struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd);
const struct acc_desc *acc_desc = drv->acc_desc; const struct acc_desc *acc_desc = drv->acc_desc;
int ret = 0; int ret;
mutex_lock(&drv->lock); guard(mutex)(&drv->lock);
dev_dbg(drv->dev, "attach callback for: %s\n", dev_name(dev)); dev_dbg(drv->dev, "attach callback for: %s\n", dev_name(dev));
...@@ -1457,7 +1447,7 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain, ...@@ -1457,7 +1447,7 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
* additional initialization when further CPUs get attached. * additional initialization when further CPUs get attached.
*/ */
if (drv->attached_cpu_dev) if (drv->attached_cpu_dev)
goto unlock; return 0;
/* /*
* cpr_scale_voltage() requires the direction (if we are changing * cpr_scale_voltage() requires the direction (if we are changing
...@@ -1469,12 +1459,10 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain, ...@@ -1469,12 +1459,10 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
* the first time cpr_set_performance_state() is called. * the first time cpr_set_performance_state() is called.
*/ */
drv->cpu_clk = devm_clk_get(dev, NULL); drv->cpu_clk = devm_clk_get(dev, NULL);
if (IS_ERR(drv->cpu_clk)) { if (IS_ERR(drv->cpu_clk))
ret = PTR_ERR(drv->cpu_clk); return dev_err_probe(drv->dev, PTR_ERR(drv->cpu_clk),
if (ret != -EPROBE_DEFER) "could not get cpu clk\n");
dev_err(drv->dev, "could not get cpu clk: %d\n", ret);
goto unlock;
}
drv->attached_cpu_dev = dev; drv->attached_cpu_dev = dev;
dev_dbg(drv->dev, "using cpu clk from: %s\n", dev_dbg(drv->dev, "using cpu clk from: %s\n",
...@@ -1491,42 +1479,39 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain, ...@@ -1491,42 +1479,39 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
ret = dev_pm_opp_get_opp_count(&drv->pd.dev); ret = dev_pm_opp_get_opp_count(&drv->pd.dev);
if (ret < 0) { if (ret < 0) {
dev_err(drv->dev, "could not get OPP count\n"); dev_err(drv->dev, "could not get OPP count\n");
goto unlock; return ret;
} }
drv->num_corners = ret; drv->num_corners = ret;
if (drv->num_corners < 2) { if (drv->num_corners < 2) {
dev_err(drv->dev, "need at least 2 OPPs to use CPR\n"); dev_err(drv->dev, "need at least 2 OPPs to use CPR\n");
ret = -EINVAL; return -EINVAL;
goto unlock;
} }
drv->corners = devm_kcalloc(drv->dev, drv->num_corners, drv->corners = devm_kcalloc(drv->dev, drv->num_corners,
sizeof(*drv->corners), sizeof(*drv->corners),
GFP_KERNEL); GFP_KERNEL);
if (!drv->corners) { if (!drv->corners)
ret = -ENOMEM; return -ENOMEM;
goto unlock;
}
ret = cpr_corner_init(drv); ret = cpr_corner_init(drv);
if (ret) if (ret)
goto unlock; return ret;
cpr_set_loop_allowed(drv); cpr_set_loop_allowed(drv);
ret = cpr_init_parameters(drv); ret = cpr_init_parameters(drv);
if (ret) if (ret)
goto unlock; return ret;
/* Configure CPR HW but keep it disabled */ /* Configure CPR HW but keep it disabled */
ret = cpr_config(drv); ret = cpr_config(drv);
if (ret) if (ret)
goto unlock; return ret;
ret = cpr_find_initial_corner(drv); ret = cpr_find_initial_corner(drv);
if (ret) if (ret)
goto unlock; return ret;
if (acc_desc->config) if (acc_desc->config)
regmap_multi_reg_write(drv->tcsr, acc_desc->config, regmap_multi_reg_write(drv->tcsr, acc_desc->config,
...@@ -1541,10 +1526,7 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain, ...@@ -1541,10 +1526,7 @@ static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
dev_info(drv->dev, "driver initialized with %u OPPs\n", dev_info(drv->dev, "driver initialized with %u OPPs\n",
drv->num_corners); drv->num_corners);
unlock: return 0;
mutex_unlock(&drv->lock);
return ret;
} }
static int cpr_debug_info_show(struct seq_file *s, void *unused) static int cpr_debug_info_show(struct seq_file *s, void *unused)
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/ /* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/
#include <linux/cleanup.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -775,9 +776,9 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain, ...@@ -775,9 +776,9 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
unsigned int level) unsigned int level)
{ {
struct rpmhpd *pd = domain_to_rpmhpd(domain); struct rpmhpd *pd = domain_to_rpmhpd(domain);
int ret = 0, i; int ret, i;
mutex_lock(&rpmhpd_lock); guard(mutex)(&rpmhpd_lock);
for (i = 0; i < pd->level_count; i++) for (i = 0; i < pd->level_count; i++)
if (level <= pd->level[i]) if (level <= pd->level[i])
...@@ -797,14 +798,12 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain, ...@@ -797,14 +798,12 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
ret = rpmhpd_aggregate_corner(pd, i); ret = rpmhpd_aggregate_corner(pd, i);
if (ret) if (ret)
goto out; return ret;
} }
pd->corner = i; pd->corner = i;
out:
mutex_unlock(&rpmhpd_lock);
return ret; return 0;
} }
static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
#include <linux/cleanup.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -1024,20 +1025,17 @@ static int rpmpd_power_on(struct generic_pm_domain *domain) ...@@ -1024,20 +1025,17 @@ static int rpmpd_power_on(struct generic_pm_domain *domain)
int ret; int ret;
struct rpmpd *pd = domain_to_rpmpd(domain); struct rpmpd *pd = domain_to_rpmpd(domain);
mutex_lock(&rpmpd_lock); guard(mutex)(&rpmpd_lock);
ret = rpmpd_send_enable(pd, true); ret = rpmpd_send_enable(pd, true);
if (ret) if (ret)
goto out; return ret;
pd->enabled = true; pd->enabled = true;
if (pd->corner) if (pd->corner)
ret = rpmpd_aggregate_corner(pd); ret = rpmpd_aggregate_corner(pd);
out:
mutex_unlock(&rpmpd_lock);
return ret; return ret;
} }
...@@ -1060,27 +1058,21 @@ static int rpmpd_power_off(struct generic_pm_domain *domain) ...@@ -1060,27 +1058,21 @@ static int rpmpd_power_off(struct generic_pm_domain *domain)
static int rpmpd_set_performance(struct generic_pm_domain *domain, static int rpmpd_set_performance(struct generic_pm_domain *domain,
unsigned int state) unsigned int state)
{ {
int ret = 0;
struct rpmpd *pd = domain_to_rpmpd(domain); struct rpmpd *pd = domain_to_rpmpd(domain);
if (state > pd->max_state) if (state > pd->max_state)
state = pd->max_state; state = pd->max_state;
mutex_lock(&rpmpd_lock); guard(mutex)(&rpmpd_lock);
pd->corner = state; pd->corner = state;
/* Always send updates for vfc and vfl */ /* Always send updates for vfc and vfl */
if (!pd->enabled && pd->key != cpu_to_le32(KEY_FLOOR_CORNER) && if (!pd->enabled && pd->key != cpu_to_le32(KEY_FLOOR_CORNER) &&
pd->key != cpu_to_le32(KEY_FLOOR_LEVEL)) pd->key != cpu_to_le32(KEY_FLOOR_LEVEL))
goto out; return 0;
ret = rpmpd_aggregate_corner(pd); return rpmpd_aggregate_corner(pd);
out:
mutex_unlock(&rpmpd_lock);
return ret;
} }
static int rpmpd_probe(struct platform_device *pdev) static int rpmpd_probe(struct platform_device *pdev)
......
This diff is collapsed.
/* 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
...@@ -198,8 +198,11 @@ struct generic_pm_domain { ...@@ -198,8 +198,11 @@ struct generic_pm_domain {
spinlock_t slock; spinlock_t slock;
unsigned long lock_flags; 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) 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, ...@@ -473,6 +476,9 @@ struct device *dev_pm_domain_attach_by_name(struct device *dev,
int dev_pm_domain_attach_list(struct device *dev, int dev_pm_domain_attach_list(struct device *dev,
const struct dev_pm_domain_attach_data *data, const struct dev_pm_domain_attach_data *data,
struct dev_pm_domain_list **list); 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(struct device *dev, bool power_off);
void dev_pm_domain_detach_list(struct dev_pm_domain_list *list); void dev_pm_domain_detach_list(struct dev_pm_domain_list *list);
int dev_pm_domain_start(struct device *dev); int dev_pm_domain_start(struct device *dev);
...@@ -499,6 +505,14 @@ static inline int dev_pm_domain_attach_list(struct device *dev, ...@@ -499,6 +505,14 @@ static inline int dev_pm_domain_attach_list(struct device *dev,
{ {
return 0; 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(struct device *dev, bool power_off) {}
static inline void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) {} static inline void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) {}
static inline int dev_pm_domain_start(struct device *dev) static inline int dev_pm_domain_start(struct device *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment