[PATCH 2/2] drm/imagination: Add utility function to write and read back register

From: Alexandru Dadu

Date: Tue Oct 06 2026 - 07:07:53 EST


From: Alessio Belle <alessio.belle@xxxxxxxxxx>

Used to avoid repeating the same pattern multiple times.

Signed-off-by: Alessio Belle <alessio.belle@xxxxxxxxxx>
Signed-off-by: Alexandru Dadu <alexandru.dadu@xxxxxxxxxx>
---
drivers/gpu/drm/imagination/pvr_device.h | 28 ++++++++++++++++++++++++++
drivers/gpu/drm/imagination/pvr_fw_meta.c | 5 ++---
drivers/gpu/drm/imagination/pvr_fw_startstop.c | 21 ++++++-------------
3 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h
index d51c57cf9332..c246122b4caf 100644
--- a/drivers/gpu/drm/imagination/pvr_device.h
+++ b/drivers/gpu/drm/imagination/pvr_device.h
@@ -606,6 +606,34 @@ pvr_cr_write64(struct pvr_device *pvr_dev, u32 reg, u64 val)
iowrite64(val, pvr_dev->regs + reg);
}

+/**
+ * pvr_cr_write_fenced32() - Write to a 32-bit register in a PowerVR device and fence the write
+ * @pvr_dev: Target PowerVR device.
+ * @reg: Target register.
+ * @val: Value to write.
+ */
+static __always_inline void
+pvr_cr_write_fenced32(struct pvr_device *pvr_dev, u32 reg, u32 val)
+{
+ pvr_cr_write32(pvr_dev, reg, val);
+ /* Read back register to fence previous write in order to clear the SOCIF pipeline */
+ (void)pvr_cr_read32(pvr_dev, reg);
+}
+
+/**
+ * pvr_cr_write_fenced64() - Write to a 64-bit register in a PowerVR device and fence the write
+ * @pvr_dev: Target PowerVR device.
+ * @reg: Target register.
+ * @val: Value to write.
+ */
+static __always_inline void
+pvr_cr_write_fenced64(struct pvr_device *pvr_dev, u32 reg, u64 val)
+{
+ pvr_cr_write64(pvr_dev, reg, val);
+ /* Read back register to fence previous write in order to clear the SOCIF pipeline */
+ (void)pvr_cr_read64(pvr_dev, reg);
+}
+
/**
* pvr_cr_poll_reg32() - Wait for a 32-bit register to match a given value by
* polling
diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.c b/drivers/gpu/drm/imagination/pvr_fw_meta.c
index 84f568b5510f..38a91dcb66cb 100644
--- a/drivers/gpu/drm/imagination/pvr_fw_meta.c
+++ b/drivers/gpu/drm/imagination/pvr_fw_meta.c
@@ -48,9 +48,8 @@ pvr_meta_cr_read32(struct pvr_device *pvr_dev, u32 reg_addr, u32 *reg_value_out)
return err;

/* Issue a Read. */
- pvr_cr_write32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0,
- reg_addr | ROGUE_CR_META_SP_MSLVCTRL0_RD_EN);
- (void)pvr_cr_read32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0); /* Fence write. */
+ pvr_cr_write_fenced32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0,
+ reg_addr | ROGUE_CR_META_SP_MSLVCTRL0_RD_EN);

/* Wait for Slave Port to be Ready. */
err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL1,
diff --git a/drivers/gpu/drm/imagination/pvr_fw_startstop.c b/drivers/gpu/drm/imagination/pvr_fw_startstop.c
index 34c757267a22..7db7f16e62fd 100644
--- a/drivers/gpu/drm/imagination/pvr_fw_startstop.c
+++ b/drivers/gpu/drm/imagination/pvr_fw_startstop.c
@@ -126,29 +126,21 @@ pvr_fw_start(struct pvr_device *pvr_dev)
* Disable the default sys_bus_secure protection to perform
* minimal setup.
*/
- pvr_cr_write32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE, 0);
- (void)pvr_cr_read32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE); /* Fence write */
+ pvr_cr_write_fenced32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE, 0);
}

if (pvr_dev->fw_dev.processor_type == PVR_FW_PROCESSOR_TYPE_RISCV)
pvr_cr_write32(pvr_dev, ROGUE_CR_FWCORE_BOOT, 0);

/* Set Rogue in soft-reset. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask);
-
- /* Read soft-reset to fence previous write in order to clear the SOCIF pipeline. */
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
+ pvr_cr_write_fenced64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask);

/* Take Rascal and Dust out of reset. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET,
- soft_reset_mask ^ ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN);
-
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
+ pvr_cr_write_fenced64(pvr_dev, ROGUE_CR_SOFT_RESET,
+ soft_reset_mask ^ ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN);

/* Take everything out of reset but the FW processor. */
- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_GARTEN_EN);
-
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
+ pvr_cr_write_fenced64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_GARTEN_EN);

err = rogue_slc_init(pvr_dev);
if (err)
@@ -168,8 +160,7 @@ pvr_fw_start(struct pvr_device *pvr_dev)
/* Need to wait for at least 16 cycles before taking the FW processor out of reset ... */
udelay(3);

- pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, 0x0);
- (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET);
+ pvr_cr_write_fenced64(pvr_dev, ROGUE_CR_SOFT_RESET, 0x0);

/* ... and afterwards. */
udelay(3);

--
2.43.0