[PATCH 2/3] soc: xilinx: route PMC TAP register access through firmware

Akshay Belsare <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
The Versal Net and Versal Gen 2 implementations of soc_detection()
currently access the PMC TAP IDCODE, VERSION, and USERCODE registers
directly without any firmware abstraction.
 
Introduce dedicated helpers for each register access:
zynqmp_pm_get_pmc_tap_idcode(),
zynqmp_pm_get_pmc_tap_version(), and
zynqmp_pm_get_pmc_tap_usercode().
 
Implement these helpers as weak platform defaults, with a common
firmware-backed override in firmware-zynqmp.c. The firmware
implementation accesses the registers through IOCTL_READ_REG using the
new PM_REGNODE_PMC_TAP register node, following the same mechanism used
by zynqmp_pm_get_pmc_multi_boot_reg() for PMC_GLOBAL register access.
 
This change removes direct PMC TAP register accesses from the SoC
detection path and provides a consistent firmware abstraction across
supported platforms.

Signed-off-by: Akshay Belsare <[email protected]>
---
 arch/arm/mach-versal-net/cpu.c                | 21 ++++++++--
 .../mach-versal-net/include/mach/sys_proto.h  |  4 ++
 arch/arm/mach-versal2/cpu.c                   | 21 ++++++++--
 .../arm/mach-versal2/include/mach/sys_proto.h |  4 ++
 drivers/firmware/firmware-zynqmp.c            | 40 +++++++++++++++++++
 include/zynqmp_firmware.h                     |  4 ++
 6 files changed, 88 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-versal-net/cpu.c b/arch/arm/mach-versal-net/cpu.c
index 54d8496a5e8..5ba2295e4f8 100644
--- a/arch/arm/mach-versal-net/cpu.c
+++ b/arch/arm/mach-versal-net/cpu.c
@@ -193,13 +193,13 @@ bool soc_detection(void)
 {
 	u32 version, ps_version;
 
-	version = readl(PMC_TAP_VERSION);
+	version = zynqmp_pm_get_pmc_tap_version();
 	platform_id = FIELD_GET(PLATFORM_MASK, version);
 	ps_version = FIELD_GET(PS_VERSION_MASK, version);
 
 	debug("idcode %x, version %x, usercode %x\n",
-	      readl(PMC_TAP_IDCODE), version,
-	      readl(PMC_TAP_USERCODE));
+	      zynqmp_pm_get_pmc_tap_idcode(), version,
+	      zynqmp_pm_get_pmc_tap_usercode());
 
 	debug("pmc_ver %lx, ps version %x, rtl version %lx\n",
 	      FIELD_GET(PMC_VERSION_MASK, version),
@@ -250,6 +250,21 @@ __weak int xilinx_pm_get_chipid(u32 *idcode, u32 *version)
 	return 0;
 }
 
+__weak u32 zynqmp_pm_get_pmc_tap_idcode(void)
+{
+	return readl(PMC_TAP_IDCODE);
+}
+
+__weak u32 zynqmp_pm_get_pmc_tap_version(void)
+{
+	return readl(PMC_TAP_VERSION);
+}
+
+__weak u32 zynqmp_pm_get_pmc_tap_usercode(void)
+{
+	return readl(PMC_TAP_USERCODE);
+}
+
 U_BOOT_DRVINFO(soc_xilinx_versal_net) = {
 	.name = "soc_xilinx_versal_net",
 };
diff --git a/arch/arm/mach-versal-net/include/mach/sys_proto.h b/arch/arm/mach-versal-net/include/mach/sys_proto.h
index bfe9df76b0b..877a7e6a0c3 100644
--- a/arch/arm/mach-versal-net/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal-net/include/mach/sys_proto.h
@@ -15,3 +15,7 @@ u8 versal_net_get_bootmode(void);
 u32 versal_net_bootmode_reg(void);
 /* Overridable chip ID accessor: weak MMIO default, firmware override */
 int xilinx_pm_get_chipid(u32 *idcode, u32 *version);
+/* Overridable PMC TAP register accessors: weak MMIO default, firmware override */
+u32 zynqmp_pm_get_pmc_tap_idcode(void);
+u32 zynqmp_pm_get_pmc_tap_version(void);
+u32 zynqmp_pm_get_pmc_tap_usercode(void);
diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c
index fc7cdbaaa65..24a02c38462 100644
--- a/arch/arm/mach-versal2/cpu.c
+++ b/arch/arm/mach-versal2/cpu.c
@@ -290,13 +290,13 @@ bool soc_detection(void)
 {
 	u32 version, ps_version;
 
-	version = readl(PMC_TAP_VERSION);
+	version = zynqmp_pm_get_pmc_tap_version();
 	platform_id = FIELD_GET(PLATFORM_MASK, version);
 	ps_version = FIELD_GET(PS_VERSION_MASK, version);
 
 	debug("idcode %x, version %x, usercode %x\n",
-	      readl(PMC_TAP_IDCODE), version,
-	      readl(PMC_TAP_USERCODE));
+	      zynqmp_pm_get_pmc_tap_idcode(), version,
+	      zynqmp_pm_get_pmc_tap_usercode());
 
 	debug("pmc_ver %lx, ps version %x, rtl version %lx\n",
 	      FIELD_GET(PMC_VERSION_MASK, version),
@@ -323,6 +323,21 @@ __weak int xilinx_pm_get_chipid(u32 *idcode, u32 *version)
 	return 0;
 }
 
+__weak u32 zynqmp_pm_get_pmc_tap_idcode(void)
+{
+	return readl(PMC_TAP_IDCODE);
+}
+
+__weak u32 zynqmp_pm_get_pmc_tap_version(void)
+{
+	return readl(PMC_TAP_VERSION);
+}
+
+__weak u32 zynqmp_pm_get_pmc_tap_usercode(void)
+{
+	return readl(PMC_TAP_USERCODE);
+}
+
 U_BOOT_DRVINFO(soc_amd_versal2) = {
 	.name = "soc_amd_versal2",
 };
diff --git a/arch/arm/mach-versal2/include/mach/sys_proto.h b/arch/arm/mach-versal2/include/mach/sys_proto.h
index 1a23f8dd425..fcc2e75c89a 100644
--- a/arch/arm/mach-versal2/include/mach/sys_proto.h
+++ b/arch/arm/mach-versal2/include/mach/sys_proto.h
@@ -23,6 +23,10 @@ u8 versal2_get_bootmode(void);
 void versal2_timer_setup(void);
 /* Overridable chip ID accessor: weak MMIO default, firmware override */
 int xilinx_pm_get_chipid(u32 *idcode, u32 *version);
+/* Overridable PMC TAP register accessors: weak MMIO default, firmware override */
+u32 zynqmp_pm_get_pmc_tap_idcode(void);
+u32 zynqmp_pm_get_pmc_tap_version(void);
+u32 zynqmp_pm_get_pmc_tap_usercode(void);
 
 int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us);
 int zynqmp_pm_wait_sram_init_done(u32 timeout_us);
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index ad759849fe4..7a922fe544b 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -510,6 +510,46 @@ u32 versal2_pmc_multi_boot(void)
 }
 #endif
 
+#if defined(CONFIG_ARCH_VERSAL_NET) || defined(CONFIG_ARCH_VERSAL2)
+static u32 zynqmp_pm_get_pmc_tap_reg(u32 offset)
+{
+	int ret;
+	u32 ret_payload[PAYLOAD_ARG_CNT];
+
+	ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG);
+	if (ret) {
+		printf("%s: IOCTL_READ_REG is not supported failed with error code: %d\n"
+		       , __func__, ret);
+		return 0;
+	}
+
+	ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_TAP, IOCTL_READ_REG,
+				offset, 0, 0, 0, ret_payload);
+	if (ret) {
+		printf("%s: node 0x%x: pmc_tap offset 0x%x failed\n",
+		       __func__, PM_REGNODE_PMC_TAP, offset);
+		return 0;
+	}
+
+	return ret_payload[1];
+}
+
+u32 zynqmp_pm_get_pmc_tap_idcode(void)
+{
+	return zynqmp_pm_get_pmc_tap_reg(PMC_TAP_IDCODE_OFFSET);
+}
+
+u32 zynqmp_pm_get_pmc_tap_version(void)
+{
+	return zynqmp_pm_get_pmc_tap_reg(PMC_TAP_VERSION_OFFSET);
+}
+
+u32 zynqmp_pm_get_pmc_tap_usercode(void)
+{
+	return zynqmp_pm_get_pmc_tap_reg(PMC_TAP_USERCODE_OFFSET);
+}
+#endif
+
 int zynqmp_pm_feature(const u32 api_id)
 {
 	int ret;
diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h
index f753a67ac27..0293bd15a2e 100644
--- a/include/zynqmp_firmware.h
+++ b/include/zynqmp_firmware.h
@@ -533,11 +533,15 @@ extern smc_call_handler_t __data smc_call_handler;
 
 #define PM_REGNODE_PMC_IOU_SLCR		0x30000002
 #define PM_REGNODE_EFUSE_CACHE		0x30000003
+#define PM_REGNODE_PMC_TAP		0x30000005
 #define PM_REG_PGGS3			0x30004003
 
 #define SRAM_CSR_OFFSET			0x104C
 #define TXRX_CFGRDY_OFFSET		0x1054
 #define UFS_CAL_1_OFFSET		0xBE8
+#define PMC_TAP_IDCODE_OFFSET		0x0
+#define PMC_TAP_VERSION_OFFSET		0x4
+#define PMC_TAP_USERCODE_OFFSET	0x8
 
 #define PMC_GLOBAL_PGGS3_REG_NODE	0x1824C005
 
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.