Add zynqmp_pm_get_pmc_global_pggs_reg() to read PMC Global PGGS3
and PGGS4 registers via firmware IOCTL. Supports IOCTL_READ_PGGS
as the preferred path and falls back to IOCTL_READ_REG for older
PLM firmware versions that do not support IOCTL_READ_PGGS.

Signed-off-by: Padmarao Begari <[email protected]>
---
 drivers/firmware/firmware-zynqmp.c | 54 +++++++++++++++++++++++++++++-
 include/zynqmp_firmware.h          |  4 +++
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/firmware-zynqmp.c 
b/drivers/firmware/firmware-zynqmp.c
index fb583580ebe..ea14ed4ef95 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -3,7 +3,7 @@
  * Xilinx Zynq MPSoC Firmware driver
  *
  * Copyright (C) 2018-2019 Xilinx, Inc.
- * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc.
+ * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc.
  */
 
 #include <asm/arch/hardware.h>
@@ -197,6 +197,58 @@ int zynqmp_pm_ufs_cal_reg(u32 *value)
        *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET);
        return 0;
 }
+#endif /* CONFIG_ARCH_VERSAL2 */
+
+#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2)
+u32 zynqmp_pm_get_pmc_global_pggs_reg(u32 reg_addr)
+{
+       int ret;
+       u32 value = 0;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+
+       if (reg_addr == PMC_GLOBAL_PGGS3_REG) {
+               value = 0;
+       } else if (reg_addr == PMC_GLOBAL_PGGS4_REG) {
+               value = 1;
+       } else {
+               printf("%s: not supported pggs register 0x%x\n",
+                      __func__, reg_addr);
+               return 0;
+       }
+
+       ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_PGGS);
+       if (ret) {
+               ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG);
+               if (ret) {
+                       printf("%s: IOCTL_READ_REG is not supported : %d\n"
+                               , __func__, ret);
+                       return 0;
+               }
+
+               /* find node ID from the pggs3 offset */
+               value = PM_REG_PGGS3 + value;
+
+               ret = xilinx_pm_request(PM_IOCTL, value,
+                                       IOCTL_READ_REG, 0, 0, 0, 0,
+                                       ret_payload);
+               if (ret) {
+                       printf("%s: node 0x%x get pggs register failed\n",
+                              __func__, value);
+                       return 0;
+               }
+       } else {
+               ret = xilinx_pm_request(PM_IOCTL, PMC_GLOBAL_PGGS3_REG_NODE,
+                                       IOCTL_READ_PGGS, value, 0, 0, 0,
+                                       ret_payload);
+               if (ret) {
+                       printf("%s: node 0x%x get pggs register failed\n",
+                              __func__, PMC_GLOBAL_PGGS3_REG_NODE);
+                       return 0;
+               }
+       }
+
+       return ret_payload[1];
+}
 #endif
 
 int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 
value)
diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h
index f5e72625e53..0e545e3db1b 100644
--- a/include/zynqmp_firmware.h
+++ b/include/zynqmp_firmware.h
@@ -470,6 +470,7 @@ int zynqmp_pm_ufs_sram_csr_read(u32 *value);
 int zynqmp_pm_ufs_sram_csr_write(u32 *value);
 int zynqmp_pm_ufs_cal_reg(u32 *value);
 u32 zynqmp_pm_get_pmc_multi_boot_reg(void);
+u32 zynqmp_pm_get_pmc_global_pggs_reg(u32 reg_addr);
 
 /* Type of Config Object */
 #define PM_CONFIG_OBJECT_TYPE_BASE     0x1U
@@ -534,4 +535,7 @@ extern smc_call_handler_t __data smc_call_handler;
 
 #define PM_DEV_OSPI            (0x1822402aU)
 
+#define PM_REG_PGGS3   0x30004003
+#define PMC_GLOBAL_PGGS3_REG_NODE      0x1824C005
+
 #endif /* _ZYNQMP_FIRMWARE_H_ */
-- 
2.34.1

Reply via email to