summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/domain/Kconfig8
-rw-r--r--drivers/power/domain/Makefile1
-rw-r--r--drivers/power/domain/altr-pmgr-agilex5.c112
-rw-r--r--drivers/power/pmic/axp.c1
-rw-r--r--drivers/power/regulator/axp_regulator.c1
-rw-r--r--drivers/power/regulator/regulator-uclass.c21
6 files changed, 135 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/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);