Move the DB8500 EPOD state handling into the Ux500 power-domain driver. Keep the old regulator driver mutually exclusive with the pmdomain driver.
Assisted-by: Codex:gpt-5-5 Signed-off-by: Linus Walleij <[email protected]> --- arch/arm/mach-ux500/Kconfig | 2 +- drivers/pmdomain/st/ste-ux500-pm-domain.c | 380 ++++++++++++++++++++++-------- drivers/regulator/Kconfig | 1 + 3 files changed, 282 insertions(+), 101 deletions(-) diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index c18def269137..56636c993f49 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -26,7 +26,7 @@ menuconfig ARCH_U8500 select PL310_ERRATA_753970 if CACHE_L2X0 select PM_GENERIC_DOMAINS if PM select REGULATOR - select REGULATOR_DB8500_PRCMU + select UX500_PM_DOMAIN select REGULATOR_FIXED_VOLTAGE select SOC_BUS select RESET_CONTROLLER diff --git a/drivers/pmdomain/st/ste-ux500-pm-domain.c b/drivers/pmdomain/st/ste-ux500-pm-domain.c index 723001004690..1cd5b4985db0 100644 --- a/drivers/pmdomain/st/ste-ux500-pm-domain.c +++ b/drivers/pmdomain/st/ste-ux500-pm-domain.c @@ -6,172 +6,315 @@ * * Implements PM domains using the generic PM domain for ux500. */ +#include <linux/cleanup.h> #include <linux/device.h> +#include <linux/err.h> #include <linux/kernel.h> +#include <linux/mfd/dbx500-prcmu.h> +#include <linux/mutex.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/printk.h> #include <linux/slab.h> -#include <linux/err.h> -#include <linux/of.h> -#include <linux/pm_domain.h> #include <dt-bindings/arm/ux500_pm_domains.h> -static int pd_power_off(struct generic_pm_domain *domain) +#define UX500_EPOD_NONE NUM_EPOD_ID + +/** + * struct dbx500_powerdomain_info - dbx500 power domain information + * @genpd: generic power domain + * @epod_id: id for EPOD (power domain) + * @is_ramret: RAM retention switch for EPOD (power domain) + * @exclude_from_power_state: exclude domain from power state count + */ +struct dbx500_powerdomain_info { + struct generic_pm_domain genpd; + u16 epod_id; + bool is_ramret; + bool exclude_from_power_state; +}; + +static DEFINE_MUTEX(ux500_pd_lock); +static int power_state_active_cnt; +static bool epod_on[NUM_EPOD_ID]; +static bool epod_ramret[NUM_EPOD_ID]; + +static void power_state_active_enable(void) +{ + power_state_active_cnt++; +} + +static int power_state_active_disable(void) { - /* - * Handle the gating of the PM domain regulator here. - * - * Drivers/subsystems handling devices in the PM domain needs to perform - * register context save/restore from their respective runtime PM - * callbacks, to be able to enable PM domain gating/ungating. - */ + if (power_state_active_cnt <= 0) { + pr_err("power state: unbalanced enable/disable calls\n"); + return -EINVAL; + } + + power_state_active_cnt--; return 0; } -static int pd_power_on(struct generic_pm_domain *domain) +static int enable_epod(u16 epod_id, bool ramret) { - /* - * Handle the ungating of the PM domain regulator here. - * - * Drivers/subsystems handling devices in the PM domain needs to perform - * register context save/restore from their respective runtime PM - * callbacks, to be able to enable PM domain gating/ungating. - */ + int ret; + + if (ramret) { + if (!epod_on[epod_id]) { + ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); + if (ret < 0) + return ret; + } + epod_ramret[epod_id] = true; + } else { + ret = prcmu_set_epod(epod_id, EPOD_STATE_ON); + if (ret < 0) + return ret; + epod_on[epod_id] = true; + } + + return 0; +} + +static int disable_epod(u16 epod_id, bool ramret) +{ + int ret; + + if (ramret) { + if (!epod_on[epod_id]) { + ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); + if (ret < 0) + return ret; + } + epod_ramret[epod_id] = false; + } else { + if (epod_ramret[epod_id]) { + ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); + if (ret < 0) + return ret; + } else { + ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); + if (ret < 0) + return ret; + } + epod_on[epod_id] = false; + } + return 0; } +static int pd_power_off(struct generic_pm_domain *domain) +{ + struct dbx500_powerdomain_info *info = + container_of(domain, struct dbx500_powerdomain_info, genpd); + int ret = 0; + + guard(mutex)(&ux500_pd_lock); + if (info->epod_id < NUM_EPOD_ID) + ret = disable_epod(info->epod_id, info->is_ramret); + else if (!info->exclude_from_power_state) + ret = power_state_active_disable(); + + return ret; +} + +static int pd_power_on(struct generic_pm_domain *domain) +{ + struct dbx500_powerdomain_info *info = + container_of(domain, struct dbx500_powerdomain_info, genpd); + int ret = 0; + + guard(mutex)(&ux500_pd_lock); + if (info->epod_id < NUM_EPOD_ID) + ret = enable_epod(info->epod_id, info->is_ramret); + else if (!info->exclude_from_power_state) + power_state_active_enable(); + + return ret; +} + /* * Apart from these voltage domains there is also VSAFE which is always * on. Vape_esram0_pwr for eSRAM0 is connected to VSAFE. */ -static struct generic_pm_domain ux500_pm_domain_vape = { +static struct dbx500_powerdomain_info ux500_pm_domain_vape = { /* Vape_pwr */ - .name = "VAPE", /* 0.95 .. 1.20 V */ - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "VAPE", /* 0.95 .. 1.20 V */ + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; -static struct generic_pm_domain ux500_pm_domain_varm = { - .name = "VARM", - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_varm = { + .genpd = { + .name = "VARM", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; -static struct generic_pm_domain ux500_pm_domain_vmodem = { - .name = "VMODEM", - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_vmodem = { + .genpd = { + .name = "VMODEM", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; -static struct generic_pm_domain ux500_pm_domain_vpll = { - .name = "VPLL", /* 1.8 V */ - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_vpll = { + .genpd = { + .name = "VPLL", /* 1.8 V */ + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; /* * CHECKME: as these are used directly by peripherals as regulators, * perhaps they should stay in the regulator subsystem? */ -static struct generic_pm_domain ux500_pm_domain_vsmps1 = { - .name = "VSMPS1", /* Also called VIO (1.2V) */ - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_vsmps1 = { + .genpd = { + .name = "VSMPS1", /* Also called VIO (1.2V) */ + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; -static struct generic_pm_domain ux500_pm_domain_vsmps2 = { - .name = "VSMPS2", /* Also called VIO (1.8V) */ - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_vsmps2 = { + .genpd = { + .name = "VSMPS2", /* Also called VIO (1.8V) */ + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, + .exclude_from_power_state = true, }; -static struct generic_pm_domain ux500_pm_domain_vsmps3 = { - .name = "VSMPS3", - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_vsmps3 = { + .genpd = { + .name = "VSMPS3", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; -static struct generic_pm_domain ux500_pm_domain_vrf1 = { - .name = "VRF1", - .power_off = pd_power_off, - .power_on = pd_power_on, +static struct dbx500_powerdomain_info ux500_pm_domain_vrf1 = { + .genpd = { + .name = "VRF1", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = UX500_EPOD_NONE, }; /* The following are technically children of VAPE */ -static struct generic_pm_domain ux500_pm_domain_sva_mmdsp = { +static struct dbx500_powerdomain_info ux500_pm_domain_sva_mmdsp = { /* Vape_SVA_MMDSP_pwr */ - .name = "SVA_MMDSP", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "SVA_MMDSP", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_SVAMMDSP, }; -static struct generic_pm_domain ux500_pm_domain_sva_pipe = { +static struct dbx500_powerdomain_info ux500_pm_domain_sva_pipe = { /* Vape_SVA_pwr */ - .name = "SVA_PIPE", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "SVA_PIPE", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_SVAPIPE, }; -static struct generic_pm_domain ux500_pm_domain_sia_mmdsp = { +static struct dbx500_powerdomain_info ux500_pm_domain_sia_mmdsp = { /* Vape_SIA_MMDSP_pwr */ - .name = "SIA_MMDSP", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "SIA_MMDSP", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_SIAMMDSP, }; -static struct generic_pm_domain ux500_pm_domain_sia_pipe = { +static struct dbx500_powerdomain_info ux500_pm_domain_sia_pipe = { /* Vape_SIA_pwr */ - .name = "SIA_PIPE", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "SIA_PIPE", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_SIAPIPE, }; -static struct generic_pm_domain ux500_pm_domain_sga = { +static struct dbx500_powerdomain_info ux500_pm_domain_sga = { /* Vape_SGA_pwr */ - .name = "SGA", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "SGA", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_SGA, }; -static struct generic_pm_domain ux500_pm_domain_b2r2_mcde = { +static struct dbx500_powerdomain_info ux500_pm_domain_b2r2_mcde = { /* Vape_DSS_pwr DSS (display subsystem) */ - .name = "B2R2_MCDE", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "B2R2_MCDE", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_B2R2_MCDE, }; -static struct generic_pm_domain ux500_pm_domain_esram_12 = { +static struct dbx500_powerdomain_info ux500_pm_domain_esram_12 = { /* Vape_esram0_pwr, Vape_esram1_pwr */ - .name = "ESRAM_12", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "ESRAM_12", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_ESRAM12, }; -static struct generic_pm_domain ux500_pm_domain_esram_34 = { +static struct dbx500_powerdomain_info ux500_pm_domain_esram_34 = { /* Vape_esram3_pwr, Vape_esram4_pwr */ - .name = "ESRAM_34", - .power_off = pd_power_off, - .power_on = pd_power_on, + .genpd = { + .name = "ESRAM_34", + .power_off = pd_power_off, + .power_on = pd_power_on, + }, + .epod_id = EPOD_ID_ESRAM34, }; static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = { - [DOMAIN_VAPE] = &ux500_pm_domain_vape, - [DOMAIN_VARM] = &ux500_pm_domain_varm, - [DOMAIN_VMODEM] = &ux500_pm_domain_vmodem, - [DOMAIN_VPLL] = &ux500_pm_domain_vpll, - [DOMAIN_VSMPS1] = &ux500_pm_domain_vsmps1, - [DOMAIN_VSMPS2] = &ux500_pm_domain_vsmps2, - [DOMAIN_VSMPS3] = &ux500_pm_domain_vsmps3, - [DOMAIN_VRF1] = &ux500_pm_domain_vrf1, - [DOMAIN_SVA_MMDSP] = &ux500_pm_domain_sva_mmdsp, - [DOMAIN_SVA_PIPE] = &ux500_pm_domain_sva_pipe, - [DOMAIN_SIA_MMDSP] = &ux500_pm_domain_sia_mmdsp, - [DOMAIN_SIA_PIPE] = &ux500_pm_domain_sia_pipe, - [DOMAIN_SGA] = &ux500_pm_domain_sga, - [DOMAIN_B2R2_MCDE] = &ux500_pm_domain_b2r2_mcde, - [DOMAIN_ESRAM_12] = &ux500_pm_domain_esram_12, - [DOMAIN_ESRAM_34] = &ux500_pm_domain_esram_34, + [DOMAIN_VAPE] = &ux500_pm_domain_vape.genpd, + [DOMAIN_VARM] = &ux500_pm_domain_varm.genpd, + [DOMAIN_VMODEM] = &ux500_pm_domain_vmodem.genpd, + [DOMAIN_VPLL] = &ux500_pm_domain_vpll.genpd, + [DOMAIN_VSMPS1] = &ux500_pm_domain_vsmps1.genpd, + [DOMAIN_VSMPS2] = &ux500_pm_domain_vsmps2.genpd, + [DOMAIN_VSMPS3] = &ux500_pm_domain_vsmps3.genpd, + [DOMAIN_VRF1] = &ux500_pm_domain_vrf1.genpd, + [DOMAIN_SVA_MMDSP] = &ux500_pm_domain_sva_mmdsp.genpd, + [DOMAIN_SVA_PIPE] = &ux500_pm_domain_sva_pipe.genpd, + [DOMAIN_SIA_MMDSP] = &ux500_pm_domain_sia_mmdsp.genpd, + [DOMAIN_SIA_PIPE] = &ux500_pm_domain_sia_pipe.genpd, + [DOMAIN_SGA] = &ux500_pm_domain_sga.genpd, + [DOMAIN_B2R2_MCDE] = &ux500_pm_domain_b2r2_mcde.genpd, + [DOMAIN_ESRAM_12] = &ux500_pm_domain_esram_12.genpd, + [DOMAIN_ESRAM_34] = &ux500_pm_domain_esram_34.genpd, }; static const struct of_device_id ux500_pm_domain_matches[] = { @@ -179,11 +322,44 @@ static const struct of_device_id ux500_pm_domain_matches[] = { { }, }; +static int ux500_pm_domain_add_subdomain(struct generic_pm_domain *domain) +{ + return pm_genpd_add_subdomain(&ux500_pm_domain_vape.genpd, domain); +} + +static int ux500_pm_domains_add_subdomains(void) +{ + int ret; + + ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sva_mmdsp.genpd); + if (ret) + return ret; + + ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sva_pipe.genpd); + if (ret) + return ret; + + ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sia_mmdsp.genpd); + if (ret) + return ret; + + ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sia_pipe.genpd); + if (ret) + return ret; + + ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sga.genpd); + if (ret) + return ret; + + return ux500_pm_domain_add_subdomain(&ux500_pm_domain_b2r2_mcde.genpd); +} + static int ux500_pm_domains_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct genpd_onecell_data *genpd_data; int i; + int ret; if (!np) return -ENODEV; @@ -196,7 +372,11 @@ static int ux500_pm_domains_probe(struct platform_device *pdev) genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains); for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i) - pm_genpd_init(ux500_pm_domains[i], NULL, false); + pm_genpd_init(ux500_pm_domains[i], NULL, true); + + ret = ux500_pm_domains_add_subdomains(); + if (ret) + return ret; of_genpd_add_provider_onecell(np, genpd_data); return 0; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 87554ab92801..35d1b191462c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -414,6 +414,7 @@ config REGULATOR_DBX500_PRCMU config REGULATOR_DB8500_PRCMU bool "ST-Ericsson DB8500 Voltage Domain Regulators" depends on MFD_DB8500_PRCMU + depends on !UX500_PM_DOMAIN select REGULATOR_DBX500_PRCMU help This driver supports the voltage domain regulators controlled by the -- 2.54.0
