arch: arm: agilex5: Enable power manager for Agilex5
authorAlif Zakuan Yuslaimi <alif.zakuan.yuslaimi@altera.com>
Thu, 12 Jun 2025 08:08:00 +0000 (01:08 -0700)
committerTien Fong Chee <tien.fong.chee@intel.com>
Wed, 30 Jul 2025 09:45:31 +0000 (17:45 +0800)
Agilex5 FSBL is required to disable the power of unused peripheral SRAM
blocks to reduce power consumption.

Introducing a new power manager driver for Agilex5 which will be called
as part of Agilex5 SPL initialization process.

This driver will read the peripheral handoff data obtained from the
bitstream and will power off the specified peripheral's SRAM from the
handoff data values.

Signed-off-by: Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi@altera.com>
Reviewed-by: Tien Fong Chee <tien.fong.chee@altera.com>
MAINTAINERS
arch/arm/dts/socfpga_agilex5-u-boot.dtsi
arch/arm/mach-socfpga/include/mach/handoff_soc64.h
arch/arm/mach-socfpga/spl_agilex5.c
configs/socfpga_agilex5_defconfig
doc/device-tree-bindings/power/altr,pmgr-agilex5.yaml [new file with mode: 0644]
drivers/power/domain/Kconfig
drivers/power/domain/Makefile
drivers/power/domain/altr-pmgr-agilex5.c [new file with mode: 0644]

index c4eaba5..795ff23 100644 (file)
@@ -156,6 +156,7 @@ M:  Tingting Meng <tingting.meng@altera.com>
 S:     Maintained
 T:     git https://source.denx.de/u-boot/custodians/u-boot-socfpga.git
 F:     drivers/ddr/altera/
+F:     drivers/power/domain/altr-pmgr-agilex5.c
 F:     arch/arm/mach-socfpga/
 F:     configs/socfpga_agilex5_vab_defconfig
 F:     drivers/sysreset/sysreset_socfpga*
index 874e71b..402f0be 100644 (file)
                                bootph-all;
                        };
                };
+
+               pwrmgr: pwrmgr@10d14000 {
+                       compatible = "altr,pmgr-agilex5";
+                       reg = <0x10d14000 0x100>;
+                       bootph-all;
+               };
        };
 };
 
index 763b077..04203cc 100644 (file)
@@ -68,6 +68,7 @@
 #define SOC64_HANDOFF_CLOCK            (SOC64_HANDOFF_BASE + 0x580)
 #if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX5)
 #define SOC64_HANDOFF_PERI             (SOC64_HANDOFF_BASE + 0x620)
+#define SOC64_HANDOFF_PERI_LEN         1
 #define SOC64_HANDOFF_SDRAM            (SOC64_HANDOFF_BASE + 0x634)
 #define SOC64_HANDOFF_SDRAM_LEN                5
 #endif
index a9aad53..2a13301 100644 (file)
@@ -96,6 +96,12 @@ void board_init_f(ulong dummy)
                hang();
        }
 
+       ret = uclass_get_device(UCLASS_POWER_DOMAIN, 0, &dev);
+       if (ret) {
+               debug("PSS SRAM power-off failed: %d\n", ret);
+               hang();
+       }
+
        if (IS_ENABLED(CONFIG_SPL_ALTERA_SDRAM)) {
                ret = uclass_get_device(UCLASS_RAM, 0, &dev);
                if (ret) {
index 33a6221..7dbb1b4 100644 (file)
@@ -103,3 +103,5 @@ CONFIG_DESIGNWARE_WATCHDOG=y
 CONFIG_WDT=y
 # CONFIG_SPL_USE_TINY_PRINTF is not set
 CONFIG_PANIC_HANG=y
+CONFIG_SPL_POWER_DOMAIN=y
+CONFIG_AGILEX5_PMGR_POWER_DOMAIN=y
diff --git a/doc/device-tree-bindings/power/altr,pmgr-agilex5.yaml b/doc/device-tree-bindings/power/altr,pmgr-agilex5.yaml
new file mode 100644 (file)
index 0000000..af7aeaa
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/altr,pmgr-agilex5.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Altera Agilex5 Power Manager
+
+maintainers:
+  - name: Alif Zakuan Yuslaimi
+    email: alif.zakuan.yuslaimi@altera.com
+
+description: |
+  This controller will read the peripheral handoff data obtained from the
+  bitstream and will power gate the specified peripheral's SRAM from the
+  handoff data values to reduce power consumption.
+
+properties:
+  compatible:
+    const: "altr,pmgr-agilex5"
+
+  reg:
+    maxItems: 1
+
+  bootph-all: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    pwrmgr: pwrmgr@10d14000 {
+      compatible = "altr,pmgr-agilex5";
+      reg = <0x10d14000 0x100>;
+      bootph-all;
+    };
index 5f5218b..ebf5d82 100644 (file)
@@ -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
index 4d20c97..8e03f62 100644 (file)
@@ -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 (file)
index 0000000..257e8b2
--- /dev/null
@@ -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),
+};