diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/domain/Kconfig | 8 | ||||
-rw-r--r-- | drivers/power/domain/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/domain/altr-pmgr-agilex5.c | 112 | ||||
-rw-r--r-- | drivers/power/domain/imx8m-power-domain.c | 2 | ||||
-rw-r--r-- | drivers/power/pmic/axp.c | 1 | ||||
-rw-r--r-- | drivers/power/regulator/axp_regulator.c | 1 | ||||
-rw-r--r-- | drivers/power/regulator/regulator-uclass.c | 21 |
7 files changed, 137 insertions, 9 deletions
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 5f5218bd8b5..ebf5d828cb0 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -18,6 +18,14 @@ config APPLE_PMGR_POWER_DOMAIN This driver is needed to power on parts of the SoC that have not been powered on by previous boot stages. +config AGILEX5_PMGR_POWER_DOMAIN + bool "Enable the Agilex5 PMGR power domain driver" + depends on SPL_POWER_DOMAIN + help + Enable support for power gating peripherals' SRAM specified in + the handoff data values obtained from the bitstream to reduce + power consumption. + config BCM6328_POWER_DOMAIN bool "Enable the BCM6328 power domain driver" depends on POWER_DOMAIN && ARCH_BMIPS diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index 4d20c97d26c..8e03f620437 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_$(PHASE_)POWER_DOMAIN) += power-domain-uclass.o obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o +obj-$(CONFIG_AGILEX5_PMGR_POWER_DOMAIN) += altr-pmgr-agilex5.o obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o diff --git a/drivers/power/domain/altr-pmgr-agilex5.c b/drivers/power/domain/altr-pmgr-agilex5.c new file mode 100644 index 00000000000..257e8b234fd --- /dev/null +++ b/drivers/power/domain/altr-pmgr-agilex5.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Altera Corporation <www.altera.com> + */ + +#include <dm.h> +#include <power-domain-uclass.h> +#include <asm/io.h> +#include <asm/arch/handoff_soc64.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <time.h> + +#define PSS_FWENCTL 0x44 +#define PSS_PGENCTL 0x48 +#define PSS_PGSTAT 0x4c + +#define DATA_MASK GENMASK(7, 0) +#define TIMEOUT_MS 1000 + +static int wait_verify_fsm(u16 timeout_ms, uintptr_t base_addr, u32 peripheral_handoff) +{ + u32 data = 0; + u32 pgstat = 0; + ulong start = get_timer(0); + + /* Wait FSM ready */ + do { + data = FIELD_GET(DATA_MASK, readl(base_addr + PSS_PGSTAT)); + if (data != 0) + break; + } while (get_timer(start) < timeout_ms); + + if (get_timer(start) >= timeout_ms) + return -ETIMEDOUT; + + /* Verify PSS SRAM power gated */ + pgstat = FIELD_GET(DATA_MASK, readl(base_addr + PSS_PGSTAT)); + if (pgstat != FIELD_GET(DATA_MASK, peripheral_handoff)) + return -EPERM; + + return 0; +} + +static int pss_sram_power_off(uintptr_t base_addr, u32 *handoff_table) +{ + u32 peripheral_handoff; + + /* Get PSS SRAM handoff data */ + peripheral_handoff = handoff_table[0]; + + /* Enable firewall for PSS SRAM */ + setbits_le32(base_addr + PSS_FWENCTL, peripheral_handoff); + + /* Wait */ + udelay(1); + + /* Power gating PSS SRAM */ + setbits_le32(base_addr + PSS_PGENCTL, peripheral_handoff); + + return wait_verify_fsm(TIMEOUT_MS, base_addr, peripheral_handoff); +} + +static int altera_pmgr_off(struct power_domain *power_domain) +{ + fdt_addr_t base_addr = dev_read_addr(power_domain->dev); + u32 handoff_table[SOC64_HANDOFF_PERI_LEN]; + int ret; + + /* Read handoff data for peripherals configuration */ + ret = socfpga_handoff_read((void *)SOC64_HANDOFF_PERI, handoff_table, + SOC64_HANDOFF_PERI_LEN); + if (ret) { + debug("%s: handoff data read failed. ret: %d\n", __func__, ret); + return ret; + } + + pss_sram_power_off(base_addr, handoff_table); + + return 0; +} + +static int altera_pmgr_probe(struct udevice *dev) +{ + struct power_domain *power_domain = dev_get_priv(dev); + + if (!power_domain) + return -EINVAL; + + power_domain->dev = dev; + + return altera_pmgr_off(power_domain); +} + +static const struct udevice_id altera_pmgr_ids[] = { + { .compatible = "altr,pmgr-agilex5" }, + { /* sentinel */ } +}; + +static struct power_domain_ops altera_pmgr_ops = { + .off = altera_pmgr_off, +}; + +U_BOOT_DRIVER(altr_pmgr) = { + .name = "altr_pmgr", + .id = UCLASS_POWER_DOMAIN, + .of_match = altera_pmgr_ids, + .ops = &altera_pmgr_ops, + .probe = altera_pmgr_probe, + .priv_auto = sizeof(struct power_domain), +}; diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index b44aae78e6d..a7e64971a2a 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -468,6 +468,8 @@ out_clk_disable: static int imx8m_power_domain_of_xlate(struct power_domain *power_domain, struct ofnode_phandle_args *args) { + power_domain->id = 0; + return 0; } diff --git a/drivers/power/pmic/axp.c b/drivers/power/pmic/axp.c index c300fd2bbc2..1204ec00f8d 100644 --- a/drivers/power/pmic/axp.c +++ b/drivers/power/pmic/axp.c @@ -89,6 +89,7 @@ static const struct udevice_id axp_pmic_ids[] = { { .compatible = "x-powers,axp221", .data = AXP221_ID }, { .compatible = "x-powers,axp223", .data = AXP223_ID }, { .compatible = "x-powers,axp313a", .data = AXP313_ID }, + { .compatible = "x-powers,axp323", .data = AXP323_ID }, { .compatible = "x-powers,axp717", .data = AXP717_ID }, { .compatible = "x-powers,axp803", .data = AXP803_ID }, { .compatible = "x-powers,axp806", .data = AXP806_ID }, diff --git a/drivers/power/regulator/axp_regulator.c b/drivers/power/regulator/axp_regulator.c index 75cdbca30f6..7794a4f5d92 100644 --- a/drivers/power/regulator/axp_regulator.c +++ b/drivers/power/regulator/axp_regulator.c @@ -318,6 +318,7 @@ static const struct axp_regulator_plat *const axp_regulators[] = { [AXP221_ID] = axp22x_regulators, [AXP223_ID] = axp22x_regulators, [AXP313_ID] = axp313_regulators, + [AXP323_ID] = axp313_regulators, [AXP717_ID] = axp717_regulators, [AXP803_ID] = axp803_regulators, [AXP806_ID] = axp806_regulators, diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 09567eb9dbb..2a59a1b79c2 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -260,13 +260,13 @@ int regulator_get_by_platname(const char *plat_name, struct udevice **devp) *devp = NULL; - for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev; - ret = uclass_find_next_device(&dev)) { - if (ret) { - dev_dbg(dev, "ret=%d\n", ret); - continue; - } + ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); + if (ret) { + dev_dbg(dev, "ret=%d\n", ret); + return ret; + } + for (; dev; uclass_find_next_device(&dev)) { uc_pdata = dev_get_uclass_plat(dev); if (!uc_pdata || strcmp(plat_name, uc_pdata->name)) continue; @@ -410,9 +410,12 @@ static bool regulator_name_is_unique(struct udevice *check_dev, int ret; int len; - for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev; - ret = uclass_find_next_device(&dev)) { - if (ret || dev == check_dev) + ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); + if (ret) + return true; + + for (; dev; uclass_find_next_device(&dev)) { + if (dev == check_dev) continue; uc_pdata = dev_get_uclass_plat(dev); |