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

Pull pmdomain updates from Ulf Hansson:
 "Core:
   - Move the generic PM domain and its governor to the pmdomain
     subsystem
   - Drop the unused pm_genpd_opp_to_performance_state()

  Providers:
   - Convert some providers to let the ->remove() callback return void
   - amlogic: Add support for G12A ISP power domain
   - arm: Move the SCPI power-domain driver to the pmdomain subsystem
   - arm: Move Kconfig options to the pmdomain subsystem
   - qcom: Update part number to X1E80100 for the rpmhpd"

* tag 'pmdomain-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm:
  PM: domains: Move genpd and its governor to the pmdomain subsystem
  PM: domains: Drop redundant header for genpd
  PM: domains: Drop the unused pm_genpd_opp_to_performance_state()
  PM: domains: fix domain_governor kernel-doc warnings
  pmdomain: xilinx/zynqmp: Convert to platform remove callback returning void
  pmdomain: qcom-cpr: Convert to platform remove callback returning void
  pmdomain: imx93-pd: Convert to platform remove callback returning void
  pmdomain: imx93-blk-ctrl: Convert to platform remove callback returning void
  pmdomain: imx8mp-blk-ctrl: Convert to platform remove callback returning void
  pmdomain: imx8m-blk-ctrl: Convert to platform remove callback returning void
  pmdomain: imx-gpcv2: Convert to platform remove callback returning void
  pmdomain: imx-gpc: Convert to platform remove callback returning void
  pmdomain: imx-pgc: Convert to platform remove callback returning void
  pmdomain: amlogic: meson-ee-pwrc: add support for G12A ISP power domain
  dt-bindings: power: meson-g12a-power: document ISP power domain
  firmware: arm_scpi: Move power-domain driver to the pmdomain dir
  pmdomain: arm_scmi: Move Kconfig options to the pmdomain subsystem
  pmdomain: qcom: rpmhpd: Update part number to X1E80100
  dt-bindings: power: rpmpd: Update part number to X1E80100
This commit is contained in:
Linus Torvalds
2024-01-12 13:54:25 -08:00
25 changed files with 100 additions and 141 deletions

View File

@@ -4,6 +4,7 @@ menu "PM Domains"
source "drivers/pmdomain/actions/Kconfig"
source "drivers/pmdomain/amlogic/Kconfig"
source "drivers/pmdomain/apple/Kconfig"
source "drivers/pmdomain/arm/Kconfig"
source "drivers/pmdomain/bcm/Kconfig"
source "drivers/pmdomain/imx/Kconfig"
source "drivers/pmdomain/mediatek/Kconfig"

View File

@@ -16,3 +16,4 @@ obj-y += sunxi/
obj-y += tegra/
obj-y += ti/
obj-y += xilinx/
obj-y += core.o governor.o

View File

@@ -47,6 +47,8 @@
#define G12A_HHI_NANOQ_MEM_PD_REG0 (0x43 << 2)
#define G12A_HHI_NANOQ_MEM_PD_REG1 (0x44 << 2)
#define G12A_HHI_ISP_MEM_PD_REG0 (0x45 << 2)
#define G12A_HHI_ISP_MEM_PD_REG1 (0x46 << 2)
struct meson_ee_pwrc;
struct meson_ee_pwrc_domain;
@@ -115,6 +117,13 @@ static struct meson_ee_pwrc_top_domain g12a_pwrc_nna = {
.iso_mask = BIT(16) | BIT(17),
};
static struct meson_ee_pwrc_top_domain g12a_pwrc_isp = {
.sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
.sleep_mask = BIT(18) | BIT(19),
.iso_reg = GX_AO_RTI_GEN_PWR_ISO0,
.iso_mask = BIT(18) | BIT(19),
};
/* Memory PD Domains */
#define VPU_MEMPD(__reg) \
@@ -231,6 +240,11 @@ static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = {
{ G12A_HHI_NANOQ_MEM_PD_REG1, GENMASK(31, 0) },
};
static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = {
{ G12A_HHI_ISP_MEM_PD_REG0, GENMASK(31, 0) },
{ G12A_HHI_ISP_MEM_PD_REG1, GENMASK(31, 0) },
};
#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
{ \
.name = __name, \
@@ -269,6 +283,8 @@ static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
[PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
[PWRC_G12A_NNA_ID] = TOP_PD("NNA", &g12a_pwrc_nna, g12a_pwrc_mem_nna,
pwrc_ee_is_powered_off),
[PWRC_G12A_ISP_ID] = TOP_PD("ISP", &g12a_pwrc_isp, g12a_pwrc_mem_isp,
pwrc_ee_is_powered_off),
};
static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {

View File

@@ -0,0 +1,37 @@
# SPDX-License-Identifier: GPL-2.0-only
config ARM_SCMI_PERF_DOMAIN
tristate "SCMI performance domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI performance domains which can be
enabled or disabled via the SCP firmware.
This driver can also be built as a module. If so, the module will be
called scmi_perf_domain.
config ARM_SCMI_POWER_DOMAIN
tristate "SCMI power domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI power domains which can be
enabled or disabled via the SCP firmware
This driver can also be built as a module. If so, the module
will be called scmi_pm_domain. Note this may needed early in boot
before rootfs may be available.
config ARM_SCPI_POWER_DOMAIN
tristate "SCPI power domain driver"
depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCPI power domains which can be
enabled or disabled via the SCP firmware
This driver can also be built as a module. If so, the module will be
called scpi_pm_domain.

View File

@@ -2,3 +2,4 @@
obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o

View File

@@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SCPI Generic power domain support.
*
* Copyright (C) 2016 ARM Ltd.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/scpi_protocol.h>
struct scpi_pm_domain {
struct generic_pm_domain genpd;
struct scpi_ops *ops;
u32 domain;
};
/*
* These device power state values are not well-defined in the specification.
* In case, different implementations use different values, we can make these
* specific to compatibles rather than getting these values from device tree.
*/
enum scpi_power_domain_state {
SCPI_PD_STATE_ON = 0,
SCPI_PD_STATE_OFF = 3,
};
#define to_scpi_pd(gpd) container_of(gpd, struct scpi_pm_domain, genpd)
static int scpi_pd_power(struct scpi_pm_domain *pd, bool power_on)
{
int ret;
enum scpi_power_domain_state state;
if (power_on)
state = SCPI_PD_STATE_ON;
else
state = SCPI_PD_STATE_OFF;
ret = pd->ops->device_set_power_state(pd->domain, state);
if (ret)
return ret;
return !(state == pd->ops->device_get_power_state(pd->domain));
}
static int scpi_pd_power_on(struct generic_pm_domain *domain)
{
struct scpi_pm_domain *pd = to_scpi_pd(domain);
return scpi_pd_power(pd, true);
}
static int scpi_pd_power_off(struct generic_pm_domain *domain)
{
struct scpi_pm_domain *pd = to_scpi_pd(domain);
return scpi_pd_power(pd, false);
}
static int scpi_pm_domain_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct scpi_pm_domain *scpi_pd;
struct genpd_onecell_data *scpi_pd_data;
struct generic_pm_domain **domains;
struct scpi_ops *scpi_ops;
int ret, num_domains, i;
scpi_ops = get_scpi_ops();
if (!scpi_ops)
return -EPROBE_DEFER;
if (!np) {
dev_err(dev, "device tree node not found\n");
return -ENODEV;
}
if (!scpi_ops->device_set_power_state ||
!scpi_ops->device_get_power_state) {
dev_err(dev, "power domains not supported in the firmware\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "num-domains", &num_domains);
if (ret) {
dev_err(dev, "number of domains not found\n");
return -EINVAL;
}
scpi_pd = devm_kcalloc(dev, num_domains, sizeof(*scpi_pd), GFP_KERNEL);
if (!scpi_pd)
return -ENOMEM;
scpi_pd_data = devm_kzalloc(dev, sizeof(*scpi_pd_data), GFP_KERNEL);
if (!scpi_pd_data)
return -ENOMEM;
domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
if (!domains)
return -ENOMEM;
for (i = 0; i < num_domains; i++, scpi_pd++) {
domains[i] = &scpi_pd->genpd;
scpi_pd->domain = i;
scpi_pd->ops = scpi_ops;
scpi_pd->genpd.name = devm_kasprintf(dev, GFP_KERNEL,
"%pOFn.%d", np, i);
if (!scpi_pd->genpd.name) {
dev_err(dev, "Failed to allocate genpd name:%pOFn.%d\n",
np, i);
continue;
}
scpi_pd->genpd.power_off = scpi_pd_power_off;
scpi_pd->genpd.power_on = scpi_pd_power_on;
/*
* Treat all power domains as off at boot.
*
* The SCP firmware itself may have switched on some domains,
* but for reference counting purpose, keep it this way.
*/
pm_genpd_init(&scpi_pd->genpd, NULL, true);
}
scpi_pd_data->domains = domains;
scpi_pd_data->num_domains = num_domains;
of_genpd_add_provider_onecell(np, scpi_pd_data);
return 0;
}
static const struct of_device_id scpi_power_domain_ids[] = {
{ .compatible = "arm,scpi-power-domains", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, scpi_power_domain_ids);
static struct platform_driver scpi_power_domain_driver = {
.driver = {
.name = "scpi_power_domain",
.of_match_table = scpi_power_domain_ids,
},
.probe = scpi_pm_domain_probe,
};
module_platform_driver(scpi_power_domain_driver);
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
MODULE_DESCRIPTION("ARM SCPI power domain driver");
MODULE_LICENSE("GPL v2");

3399
drivers/pmdomain/core.c Normal file

File diff suppressed because it is too large Load Diff

418
drivers/pmdomain/governor.c Normal file
View File

@@ -0,0 +1,418 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/base/power/domain_governor.c - Governors for device PM domains.
*
* Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
*/
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
#include <linux/hrtimer.h>
#include <linux/cpuidle.h>
#include <linux/cpumask.h>
#include <linux/ktime.h>
static int dev_update_qos_constraint(struct device *dev, void *data)
{
s64 *constraint_ns_p = data;
s64 constraint_ns;
if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
struct gpd_timing_data *td = dev_gpd_data(dev)->td;
/*
* Only take suspend-time QoS constraints of devices into
* account, because constraints updated after the device has
* been suspended are not guaranteed to be taken into account
* anyway. In order for them to take effect, the device has to
* be resumed and suspended again.
*/
constraint_ns = td ? td->effective_constraint_ns :
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
} else {
/*
* The child is not in a domain and there's no info on its
* suspend/resume latencies, so assume them to be negligible and
* take its current PM QoS constraint (that's the only thing
* known at this point anyway).
*/
constraint_ns = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY);
constraint_ns *= NSEC_PER_USEC;
}
if (constraint_ns < *constraint_ns_p)
*constraint_ns_p = constraint_ns;
return 0;
}
/**
* default_suspend_ok - Default PM domain governor routine to suspend devices.
* @dev: Device to check.
*
* Returns: true if OK to suspend, false if not OK to suspend
*/
static bool default_suspend_ok(struct device *dev)
{
struct gpd_timing_data *td = dev_gpd_data(dev)->td;
unsigned long flags;
s64 constraint_ns;
dev_dbg(dev, "%s()\n", __func__);
spin_lock_irqsave(&dev->power.lock, flags);
if (!td->constraint_changed) {
bool ret = td->cached_suspend_ok;
spin_unlock_irqrestore(&dev->power.lock, flags);
return ret;
}
td->constraint_changed = false;
td->cached_suspend_ok = false;
td->effective_constraint_ns = 0;
constraint_ns = __dev_pm_qos_resume_latency(dev);
spin_unlock_irqrestore(&dev->power.lock, flags);
if (constraint_ns == 0)
return false;
constraint_ns *= NSEC_PER_USEC;
/*
* We can walk the children without any additional locking, because
* they all have been suspended at this point and their
* effective_constraint_ns fields won't be modified in parallel with us.
*/
if (!dev->power.ignore_children)
device_for_each_child(dev, &constraint_ns,
dev_update_qos_constraint);
if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
/* "No restriction", so the device is allowed to suspend. */
td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
td->cached_suspend_ok = true;
} else if (constraint_ns == 0) {
/*
* This triggers if one of the children that don't belong to a
* domain has a zero PM QoS constraint and it's better not to
* suspend then. effective_constraint_ns is zero already and
* cached_suspend_ok is false, so bail out.
*/
return false;
} else {
constraint_ns -= td->suspend_latency_ns +
td->resume_latency_ns;
/*
* effective_constraint_ns is zero already and cached_suspend_ok
* is false, so if the computed value is not positive, return
* right away.
*/
if (constraint_ns <= 0)
return false;
td->effective_constraint_ns = constraint_ns;
td->cached_suspend_ok = true;
}
/*
* The children have been suspended already, so we don't need to take
* their suspend latencies into account here.
*/
return td->cached_suspend_ok;
}
static void update_domain_next_wakeup(struct generic_pm_domain *genpd, ktime_t now)
{
ktime_t domain_wakeup = KTIME_MAX;
ktime_t next_wakeup;
struct pm_domain_data *pdd;
struct gpd_link *link;
if (!(genpd->flags & GENPD_FLAG_MIN_RESIDENCY))
return;
/*
* Devices that have a predictable wakeup pattern, may specify
* their next wakeup. Let's find the next wakeup from all the
* devices attached to this domain and from all the sub-domains.
* It is possible that component's a next wakeup may have become
* stale when we read that here. We will ignore to ensure the domain
* is able to enter its optimal idle state.
*/
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
next_wakeup = to_gpd_data(pdd)->td->next_wakeup;
if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now))
if (ktime_before(next_wakeup, domain_wakeup))
domain_wakeup = next_wakeup;
}
list_for_each_entry(link, &genpd->parent_links, parent_node) {
struct genpd_governor_data *cgd = link->child->gd;
next_wakeup = cgd ? cgd->next_wakeup : KTIME_MAX;
if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now))
if (ktime_before(next_wakeup, domain_wakeup))
domain_wakeup = next_wakeup;
}
genpd->gd->next_wakeup = domain_wakeup;
}
static bool next_wakeup_allows_state(struct generic_pm_domain *genpd,
unsigned int state, ktime_t now)
{
ktime_t domain_wakeup = genpd->gd->next_wakeup;
s64 idle_time_ns, min_sleep_ns;
min_sleep_ns = genpd->states[state].power_off_latency_ns +
genpd->states[state].residency_ns;
idle_time_ns = ktime_to_ns(ktime_sub(domain_wakeup, now));
return idle_time_ns >= min_sleep_ns;
}
static bool __default_power_down_ok(struct dev_pm_domain *pd,
unsigned int state)
{
struct generic_pm_domain *genpd = pd_to_genpd(pd);
struct gpd_link *link;
struct pm_domain_data *pdd;
s64 min_off_time_ns;
s64 off_on_time_ns;
off_on_time_ns = genpd->states[state].power_off_latency_ns +
genpd->states[state].power_on_latency_ns;
min_off_time_ns = -1;
/*
* Check if subdomains can be off for enough time.
*
* All subdomains have been powered off already at this point.
*/
list_for_each_entry(link, &genpd->parent_links, parent_node) {
struct genpd_governor_data *cgd = link->child->gd;
s64 sd_max_off_ns = cgd ? cgd->max_off_time_ns : -1;
if (sd_max_off_ns < 0)
continue;
/*
* Check if the subdomain is allowed to be off long enough for
* the current domain to turn off and on (that's how much time
* it will have to wait worst case).
*/
if (sd_max_off_ns <= off_on_time_ns)
return false;
if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0)
min_off_time_ns = sd_max_off_ns;
}
/*
* Check if the devices in the domain can be off enough time.
*/
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
struct gpd_timing_data *td;
s64 constraint_ns;
/*
* Check if the device is allowed to be off long enough for the
* domain to turn off and on (that's how much time it will
* have to wait worst case).
*/
td = to_gpd_data(pdd)->td;
constraint_ns = td->effective_constraint_ns;
/*
* Zero means "no suspend at all" and this runs only when all
* devices in the domain are suspended, so it must be positive.
*/
if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
continue;
if (constraint_ns <= off_on_time_ns)
return false;
if (min_off_time_ns > constraint_ns || min_off_time_ns < 0)
min_off_time_ns = constraint_ns;
}
/*
* If the computed minimum device off time is negative, there are no
* latency constraints, so the domain can spend arbitrary time in the
* "off" state.
*/
if (min_off_time_ns < 0)
return true;
/*
* The difference between the computed minimum subdomain or device off
* time and the time needed to turn the domain on is the maximum
* theoretical time this domain can spend in the "off" state.
*/
genpd->gd->max_off_time_ns = min_off_time_ns -
genpd->states[state].power_on_latency_ns;
return true;
}
/**
* _default_power_down_ok - Default generic PM domain power off governor routine.
* @pd: PM domain to check.
* @now: current ktime.
*
* This routine must be executed under the PM domain's lock.
*
* Returns: true if OK to power down, false if not OK to power down
*/
static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
{
struct generic_pm_domain *genpd = pd_to_genpd(pd);
struct genpd_governor_data *gd = genpd->gd;
int state_idx = genpd->state_count - 1;
struct gpd_link *link;
/*
* Find the next wakeup from devices that can determine their own wakeup
* to find when the domain would wakeup and do it for every device down
* the hierarchy. It is not worth while to sleep if the state's residency
* cannot be met.
*/
update_domain_next_wakeup(genpd, now);
if ((genpd->flags & GENPD_FLAG_MIN_RESIDENCY) && (gd->next_wakeup != KTIME_MAX)) {
/* Let's find out the deepest domain idle state, the devices prefer */
while (state_idx >= 0) {
if (next_wakeup_allows_state(genpd, state_idx, now)) {
gd->max_off_time_changed = true;
break;
}
state_idx--;
}
if (state_idx < 0) {
state_idx = 0;
gd->cached_power_down_ok = false;
goto done;
}
}
if (!gd->max_off_time_changed) {
genpd->state_idx = gd->cached_power_down_state_idx;
return gd->cached_power_down_ok;
}
/*
* We have to invalidate the cached results for the parents, so
* use the observation that default_power_down_ok() is not
* going to be called for any parent until this instance
* returns.
*/
list_for_each_entry(link, &genpd->child_links, child_node) {
struct genpd_governor_data *pgd = link->parent->gd;
if (pgd)
pgd->max_off_time_changed = true;
}
gd->max_off_time_ns = -1;
gd->max_off_time_changed = false;
gd->cached_power_down_ok = true;
/*
* Find a state to power down to, starting from the state
* determined by the next wakeup.
*/
while (!__default_power_down_ok(pd, state_idx)) {
if (state_idx == 0) {
gd->cached_power_down_ok = false;
break;
}
state_idx--;
}
done:
genpd->state_idx = state_idx;
gd->cached_power_down_state_idx = genpd->state_idx;
return gd->cached_power_down_ok;
}
static bool default_power_down_ok(struct dev_pm_domain *pd)
{
return _default_power_down_ok(pd, ktime_get());
}
#ifdef CONFIG_CPU_IDLE
static bool cpu_power_down_ok(struct dev_pm_domain *pd)
{
struct generic_pm_domain *genpd = pd_to_genpd(pd);
struct cpuidle_device *dev;
ktime_t domain_wakeup, next_hrtimer;
ktime_t now = ktime_get();
s64 idle_duration_ns;
int cpu, i;
/* Validate dev PM QoS constraints. */
if (!_default_power_down_ok(pd, now))
return false;
if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN))
return true;
/*
* Find the next wakeup for any of the online CPUs within the PM domain
* and its subdomains. Note, we only need the genpd->cpus, as it already
* contains a mask of all CPUs from subdomains.
*/
domain_wakeup = ktime_set(KTIME_SEC_MAX, 0);
for_each_cpu_and(cpu, genpd->cpus, cpu_online_mask) {
dev = per_cpu(cpuidle_devices, cpu);
if (dev) {
next_hrtimer = READ_ONCE(dev->next_hrtimer);
if (ktime_before(next_hrtimer, domain_wakeup))
domain_wakeup = next_hrtimer;
}
}
/* The minimum idle duration is from now - until the next wakeup. */
idle_duration_ns = ktime_to_ns(ktime_sub(domain_wakeup, now));
if (idle_duration_ns <= 0)
return false;
/* Store the next domain_wakeup to allow consumers to use it. */
genpd->gd->next_hrtimer = domain_wakeup;
/*
* Find the deepest idle state that has its residency value satisfied
* and by also taking into account the power off latency for the state.
* Start at the state picked by the dev PM QoS constraint validation.
*/
i = genpd->state_idx;
do {
if (idle_duration_ns >= (genpd->states[i].residency_ns +
genpd->states[i].power_off_latency_ns)) {
genpd->state_idx = i;
return true;
}
} while (--i >= 0);
return false;
}
struct dev_power_governor pm_domain_cpu_gov = {
.suspend_ok = default_suspend_ok,
.power_down_ok = cpu_power_down_ok,
};
#endif
struct dev_power_governor simple_qos_governor = {
.suspend_ok = default_suspend_ok,
.power_down_ok = default_power_down_ok,
};
/*
* pm_domain_always_on_gov - A governor implementing an always-on policy
*/
struct dev_power_governor pm_domain_always_on_gov = {
.suspend_ok = default_suspend_ok,
};

View File

@@ -212,7 +212,7 @@ genpd_err:
return ret;
}
static int imx_pgc_power_domain_remove(struct platform_device *pdev)
static void imx_pgc_power_domain_remove(struct platform_device *pdev)
{
struct imx_pm_domain *domain = pdev->dev.platform_data;
@@ -221,8 +221,6 @@ static int imx_pgc_power_domain_remove(struct platform_device *pdev)
pm_genpd_remove(&domain->base);
imx_pgc_put_clocks(domain);
}
return 0;
}
static const struct platform_device_id imx_pgc_power_domain_id[] = {
@@ -235,7 +233,7 @@ static struct platform_driver imx_pgc_power_domain_driver = {
.name = "imx-pgc-pd",
},
.probe = imx_pgc_power_domain_probe,
.remove = imx_pgc_power_domain_remove,
.remove_new = imx_pgc_power_domain_remove,
.id_table = imx_pgc_power_domain_id,
};
builtin_platform_driver(imx_pgc_power_domain_driver)
@@ -511,7 +509,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
return 0;
}
static int imx_gpc_remove(struct platform_device *pdev)
static void imx_gpc_remove(struct platform_device *pdev)
{
struct device_node *pgc_node;
int ret;
@@ -521,7 +519,7 @@ static int imx_gpc_remove(struct platform_device *pdev)
/* bail out if DT too old and doesn't provide the necessary info */
if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
!pgc_node)
return 0;
return;
/*
* If the old DT binding is used the toplevel driver needs to
@@ -531,16 +529,20 @@ static int imx_gpc_remove(struct platform_device *pdev)
of_genpd_del_provider(pdev->dev.of_node);
ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base);
if (ret)
return ret;
if (ret) {
dev_err(&pdev->dev, "Failed to remove PU power domain (%pe)\n",
ERR_PTR(ret));
return;
}
imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base);
if (ret)
return ret;
if (ret) {
dev_err(&pdev->dev, "Failed to remove ARM power domain (%pe)\n",
ERR_PTR(ret));
return;
}
}
return 0;
}
static struct platform_driver imx_gpc_driver = {
@@ -549,6 +551,6 @@ static struct platform_driver imx_gpc_driver = {
.of_match_table = imx_gpc_dt_ids,
},
.probe = imx_gpc_probe,
.remove = imx_gpc_remove,
.remove_new = imx_gpc_remove,
};
builtin_platform_driver(imx_gpc_driver)

View File

@@ -1373,7 +1373,7 @@ out_domain_unmap:
return ret;
}
static int imx_pgc_domain_remove(struct platform_device *pdev)
static void imx_pgc_domain_remove(struct platform_device *pdev)
{
struct imx_pgc_domain *domain = pdev->dev.platform_data;
@@ -1385,8 +1385,6 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)
domain->bits.map, 0);
pm_runtime_disable(domain->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1430,7 +1428,7 @@ static struct platform_driver imx_pgc_domain_driver = {
.pm = &imx_pgc_domain_pm_ops,
},
.probe = imx_pgc_domain_probe,
.remove = imx_pgc_domain_remove,
.remove_new = imx_pgc_domain_remove,
.id_table = imx_pgc_domain_id,
};
builtin_platform_driver(imx_pgc_domain_driver)

View File

@@ -330,7 +330,7 @@ cleanup_pds:
return ret;
}
static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
static void imx8m_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
@@ -347,8 +347,6 @@ static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
dev_pm_genpd_remove_notifier(bc->bus_power_dev);
dev_pm_domain_detach(bc->bus_power_dev, true);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -888,7 +886,7 @@ MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
static struct platform_driver imx8m_blk_ctrl_driver = {
.probe = imx8m_blk_ctrl_probe,
.remove = imx8m_blk_ctrl_remove,
.remove_new = imx8m_blk_ctrl_remove,
.driver = {
.name = "imx8m-blk-ctrl",
.pm = &imx8m_blk_ctrl_pm_ops,

View File

@@ -760,7 +760,7 @@ cleanup_pds:
return ret;
}
static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
static void imx8mp_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
@@ -777,8 +777,6 @@ static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
dev_pm_genpd_remove_notifier(bc->bus_power_dev);
dev_pm_domain_detach(bc->bus_power_dev, true);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -856,7 +854,7 @@ MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match);
static struct platform_driver imx8mp_blk_ctrl_driver = {
.probe = imx8mp_blk_ctrl_probe,
.remove = imx8mp_blk_ctrl_remove,
.remove_new = imx8mp_blk_ctrl_remove,
.driver = {
.name = "imx8mp-blk-ctrl",
.pm = &imx8mp_blk_ctrl_pm_ops,

View File

@@ -306,7 +306,7 @@ cleanup_pds:
return ret;
}
static int imx93_blk_ctrl_remove(struct platform_device *pdev)
static void imx93_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
@@ -318,8 +318,6 @@ static int imx93_blk_ctrl_remove(struct platform_device *pdev)
pm_genpd_remove(&domain->genpd);
}
return 0;
}
static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
@@ -438,7 +436,7 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
static struct platform_driver imx93_blk_ctrl_driver = {
.probe = imx93_blk_ctrl_probe,
.remove = imx93_blk_ctrl_remove,
.remove_new = imx93_blk_ctrl_remove,
.driver = {
.name = "imx93-blk-ctrl",
.of_match_table = imx93_blk_ctrl_of_match,

View File

@@ -83,7 +83,7 @@ static int imx93_pd_off(struct generic_pm_domain *genpd)
return 0;
};
static int imx93_pd_remove(struct platform_device *pdev)
static void imx93_pd_remove(struct platform_device *pdev)
{
struct imx93_power_domain *domain = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -94,8 +94,6 @@ static int imx93_pd_remove(struct platform_device *pdev)
of_genpd_del_provider(np);
pm_genpd_remove(&domain->genpd);
return 0;
}
static int imx93_pd_probe(struct platform_device *pdev)
@@ -167,7 +165,7 @@ static struct platform_driver imx93_power_domain_driver = {
.of_match_table = imx93_pd_ids,
},
.probe = imx93_pd_probe,
.remove = imx93_pd_remove,
.remove_new = imx93_pd_remove,
};
module_platform_driver(imx93_power_domain_driver);

View File

@@ -1712,7 +1712,7 @@ err_remove_genpd:
return ret;
}
static int cpr_remove(struct platform_device *pdev)
static void cpr_remove(struct platform_device *pdev)
{
struct cpr_drv *drv = platform_get_drvdata(pdev);
@@ -1725,8 +1725,6 @@ static int cpr_remove(struct platform_device *pdev)
pm_genpd_remove(&drv->pd);
debugfs_remove_recursive(drv->debugfs);
return 0;
}
static const struct of_device_id cpr_match_table[] = {
@@ -1737,7 +1735,7 @@ MODULE_DEVICE_TABLE(of, cpr_match_table);
static struct platform_driver cpr_driver = {
.probe = cpr_probe,
.remove = cpr_remove,
.remove_new = cpr_remove,
.driver = {
.name = "qcom-cpr",
.of_match_table = cpr_match_table,

View File

@@ -598,8 +598,8 @@ static const struct rpmhpd_desc sc8280xp_desc = {
.num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
};
/* SC8380xp RPMH powerdomains */
static struct rpmhpd *sc8380xp_rpmhpds[] = {
/* X1E80100 RPMH powerdomains */
static struct rpmhpd *x1e80100_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
@@ -615,9 +615,9 @@ static struct rpmhpd *sc8380xp_rpmhpds[] = {
[RPMHPD_GMXC] = &gmxc,
};
static const struct rpmhpd_desc sc8380xp_desc = {
.rpmhpds = sc8380xp_rpmhpds,
.num_pds = ARRAY_SIZE(sc8380xp_rpmhpds),
static const struct rpmhpd_desc x1e80100_desc = {
.rpmhpds = x1e80100_rpmhpds,
.num_pds = ARRAY_SIZE(x1e80100_rpmhpds),
};
static const struct of_device_id rpmhpd_match_table[] = {
@@ -629,7 +629,6 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
{ .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
{ .compatible = "qcom,sc8380xp-rpmhpd", .data = &sc8380xp_desc },
{ .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
@@ -643,6 +642,7 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
{ .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
{ .compatible = "qcom,sm8650-rpmhpd", .data = &sm8650_desc },
{ .compatible = "qcom,x1e80100-rpmhpd", .data = &x1e80100_desc },
{ }
};
MODULE_DEVICE_TABLE(of, rpmhpd_match_table);

View File

@@ -293,11 +293,9 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
return 0;
}
static int zynqmp_gpd_remove(struct platform_device *pdev)
static void zynqmp_gpd_remove(struct platform_device *pdev)
{
of_genpd_del_provider(pdev->dev.parent->of_node);
return 0;
}
static void zynqmp_gpd_sync_state(struct device *dev)
@@ -315,7 +313,7 @@ static struct platform_driver zynqmp_power_domain_driver = {
.sync_state = zynqmp_gpd_sync_state,
},
.probe = zynqmp_gpd_probe,
.remove = zynqmp_gpd_remove,
.remove_new = zynqmp_gpd_remove,
};
module_platform_driver(zynqmp_power_domain_driver);