diff --git a/drivers/gpu/drm/panthor/Makefile b/drivers/gpu/drm/panthor/Makefile
index ab297637d172..e1f06396bd1d 100644
--- a/drivers/gpu/drm/panthor/Makefile
+++ b/drivers/gpu/drm/panthor/Makefile
@@ -8,6 +8,7 @@ panthor-y := \
 	panthor_gem.o \
 	panthor_gpu.o \
 	panthor_heap.o \
+	panthor_hw.o \
 	panthor_mmu.o \
 	panthor_props.o \
 	panthor_sched.o
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index 0b74dc628489..fd261e525b7b 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -18,6 +18,7 @@
 #include "panthor_device.h"
 #include "panthor_fw.h"
 #include "panthor_gpu.h"
+#include "panthor_hw.h"
 #include "panthor_mmu.h"
 #include "panthor_props.h"
 #include "panthor_regs.h"
@@ -116,6 +117,11 @@ void panthor_device_unplug(struct panthor_device *ptdev)
 	complete_all(&ptdev->unplug.done);
 }
 
+static bool panthor_device_is_initialized(struct panthor_device *ptdev)
+{
+	return !!ptdev->scheduler;
+}
+
 static void panthor_device_reset_cleanup(struct drm_device *ddev, void *data)
 {
 	struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base);
@@ -141,11 +147,14 @@ static void panthor_device_reset_work(struct work_struct *work)
 	if (!drm_dev_enter(&ptdev->base, &cookie))
 		return;
 
+	if (!panthor_device_is_initialized(ptdev))
+		return;
+
 	panthor_sched_pre_reset(ptdev);
 	panthor_fw_pre_reset(ptdev, true);
 	panthor_mmu_pre_reset(ptdev);
-	panthor_gpu_soft_reset(ptdev);
-	panthor_gpu_l2_power_on(ptdev);
+	ptdev->hw->ops.soft_reset(ptdev);
+	ptdev->hw->ops.l2_power_on(ptdev);
 	panthor_mmu_post_reset(ptdev);
 	ret = panthor_fw_post_reset(ptdev);
 	atomic_set(&ptdev->reset.pending, 0);
@@ -158,11 +167,6 @@ static void panthor_device_reset_work(struct work_struct *work)
 	}
 }
 
-static bool panthor_device_is_initialized(struct panthor_device *ptdev)
-{
-	return !!ptdev->scheduler;
-}
-
 static void panthor_device_free_page(struct drm_device *ddev, void *data)
 {
 	__free_page(data);
@@ -247,6 +251,10 @@ int panthor_device_init(struct panthor_device *ptdev)
 			return ret;
 	}
 
+	ret = panthor_hw_init(ptdev);
+	if (ret)
+		goto err_rpm_put;
+
 	ret = panthor_gpu_init(ptdev);
 	if (ret)
 		goto err_rpm_put;
diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index 60c9a67fb4a2..a984d5f9a68a 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -24,6 +24,7 @@ struct panthor_device;
 struct panthor_gpu;
 struct panthor_group_pool;
 struct panthor_heap_pool;
+struct panthor_hw;
 struct panthor_job;
 struct panthor_mmu;
 struct panthor_props;
@@ -124,6 +125,9 @@ struct panthor_device {
 	/** @csif_info: Command stream interface information. */
 	struct drm_panthor_csif_info csif_info;
 
+	/** @hw: GPU specific data */
+	struct panthor_hw *hw;
+
 	/** @gpu: GPU management data. */
 	struct panthor_gpu *gpu;
 
@@ -365,13 +369,14 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data)
 {												\
 	struct panthor_irq *pirq = data;							\
 	struct panthor_device *ptdev = pirq->ptdev;						\
+	const u64 base = ptdev->hw->map.__name ## _irq.base;					\
 												\
 	if (atomic_read(&pirq->suspended))							\
 		return IRQ_NONE;								\
-	if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT))					\
+	if (!gpu_read(ptdev, base + __reg_prefix ## _INT_STAT))					\
 		return IRQ_NONE;								\
 												\
-	gpu_write(ptdev, __reg_prefix ## _INT_MASK, 0);						\
+	gpu_write(ptdev, base + __reg_prefix ## _INT_MASK, 0);					\
 	return IRQ_WAKE_THREAD;									\
 }												\
 												\
@@ -379,40 +384,47 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da
 {												\
 	struct panthor_irq *pirq = data;							\
 	struct panthor_device *ptdev = pirq->ptdev;						\
+	const u64 base = ptdev->hw->map.__name ## _irq.base;					\
 	irqreturn_t ret = IRQ_NONE;								\
 												\
 	while (true) {										\
-		u32 status = gpu_read(ptdev, __reg_prefix ## _INT_RAWSTAT) & pirq->mask;	\
+		u32 status = gpu_read(ptdev, base + __reg_prefix ## _INT_RAWSTAT) & pirq->mask;	\
 												\
 		if (!status)									\
 			break;									\
 												\
-		gpu_write(ptdev, __reg_prefix ## _INT_CLEAR, status);				\
+		gpu_write(ptdev, base + __reg_prefix ## _INT_CLEAR, status);			\
 												\
 		__handler(ptdev, status);							\
 		ret = IRQ_HANDLED;								\
 	}											\
 												\
 	if (!atomic_read(&pirq->suspended))							\
-		gpu_write(ptdev, __reg_prefix ## _INT_MASK, pirq->mask);			\
+		gpu_write(ptdev, base + __reg_prefix ## _INT_MASK, pirq->mask);			\
 												\
 	return ret;										\
 }												\
 												\
 static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq)			\
 {												\
+	struct panthor_device *ptdev = pirq->ptdev;						\
+	const u64 base = ptdev->hw->map.__name ## _irq.base;					\
+												\
 	pirq->mask = 0;										\
-	gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, 0);					\
+	gpu_write(pirq->ptdev, base + __reg_prefix ## _INT_MASK, 0);				\
 	synchronize_irq(pirq->irq);								\
 	atomic_set(&pirq->suspended, true);							\
 }												\
 												\
 static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq, u32 mask)	\
 {												\
+	struct panthor_device *ptdev = pirq->ptdev;						\
+	const u64 base = ptdev->hw->map.__name ## _irq.base;					\
+												\
 	atomic_set(&pirq->suspended, false);							\
 	pirq->mask = mask;									\
-	gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, mask);				\
-	gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, mask);				\
+	gpu_write(pirq->ptdev, base + __reg_prefix ## _INT_CLEAR, mask);			\
+	gpu_write(pirq->ptdev, base + __reg_prefix ## _INT_MASK, mask);				\
 }												\
 												\
 static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev,			\
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 51b63d258c7a..27c2e950927b 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -21,6 +21,7 @@
 #include "panthor_fw.h"
 #include "panthor_gem.h"
 #include "panthor_gpu.h"
+#include "panthor_hw.h"
 #include "panthor_mmu.h"
 #include "panthor_props.h"
 #include "panthor_regs.h"
@@ -34,6 +35,9 @@
 #define IDLE_HYSTERESIS_US			800
 #define PWROFF_HYSTERESIS_US			10000
 
+#define MCU_BASE(ptdev) (ptdev->hw->map.mcu_control_base)
+#define JOB_BASE(ptdev) (ptdev->hw->map.job_irq.base)
+
 /**
  * struct panthor_fw_binary_hdr - Firmware binary header.
  */
@@ -1030,13 +1034,13 @@ static int panthor_fw_start(struct panthor_device *ptdev)
 
 	ptdev->fw->booted = false;
 	panthor_job_irq_resume(&ptdev->fw->irq, ~0);
-	gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_AUTO);
+	gpu_write(ptdev, MCU_BASE(ptdev) + MCU_CONTROL, MCU_CONTROL_AUTO);
 
 	if (!wait_event_timeout(ptdev->fw->req_waitqueue,
 				ptdev->fw->booted,
 				msecs_to_jiffies(1000))) {
 		if (!ptdev->fw->booted &&
-		    !(gpu_read(ptdev, JOB_INT_STAT) & JOB_INT_GLOBAL_IF))
+		    !(gpu_read(ptdev, JOB_BASE(ptdev) + JOB_INT_STAT) & JOB_INT_GLOBAL_IF))
 			timedout = true;
 	}
 
@@ -1047,7 +1051,7 @@ static int panthor_fw_start(struct panthor_device *ptdev)
 			[MCU_STATUS_HALT] = "halt",
 			[MCU_STATUS_FATAL] = "fatal",
 		};
-		u32 status = gpu_read(ptdev, MCU_STATUS);
+		u32 status = gpu_read(ptdev, MCU_BASE(ptdev) + MCU_STATUS);
 
 		drm_err(&ptdev->base, "Failed to boot MCU (status=%s)",
 			status < ARRAY_SIZE(status_str) ? status_str[status] : "unknown");
@@ -1061,8 +1065,8 @@ static void panthor_fw_stop(struct panthor_device *ptdev)
 {
 	u32 status;
 
-	gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_DISABLE);
-	if (gpu_read_poll_timeout(ptdev, MCU_STATUS, status,
+	gpu_write(ptdev, MCU_BASE(ptdev) + MCU_CONTROL, MCU_CONTROL_DISABLE);
+	if (gpu_read_poll_timeout(ptdev, MCU_BASE(ptdev) + MCU_STATUS, status,
 				  status == MCU_STATUS_DISABLED, 10, 100000))
 		drm_err(&ptdev->base, "Failed to stop MCU");
 }
@@ -1088,10 +1092,10 @@ void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang)
 
 		panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT);
 		gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
-		if (!gpu_read_poll_timeout(ptdev, MCU_STATUS, status,
-					   status == MCU_STATUS_HALT, 10,
-					   100000)) {
-			ptdev->fw->fast_reset = true;
+		if (!gpu_read_poll_timeout(ptdev, MCU_BASE(ptdev) + MCU_STATUS,
+					   status, status == MCU_STATUS_HALT,
+					   10, 100000)) {
+			ptdev->reset.fast = true;
 		} else {
 			drm_warn(&ptdev->base, "Failed to cleanly suspend MCU");
 		}
@@ -1183,7 +1187,7 @@ void panthor_fw_unplug(struct panthor_device *ptdev)
 	ptdev->fw->vm = NULL;
 
 	if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev))
-		panthor_gpu_power_off(ptdev, L2, ptdev->gpu_info.l2_present, 20000);
+		ptdev->hw->ops.l2_power_off(ptdev);
 }
 
 /**
@@ -1352,7 +1356,8 @@ int panthor_fw_init(struct panthor_device *ptdev)
 	INIT_LIST_HEAD(&fw->sections);
 	INIT_DELAYED_WORK(&fw->watchdog.ping_work, panthor_fw_ping_work);
 
-	irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "job");
+	irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev),
+				      ptdev->hw->map.job_irq.name);
 	if (irq <= 0)
 		return -ENODEV;
 
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index ec1780fe2638..9dadcea67a39 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -18,9 +18,12 @@
 
 #include "panthor_device.h"
 #include "panthor_gpu.h"
+#include "panthor_hw.h"
 #include "panthor_props.h"
 #include "panthor_regs.h"
 
+#define GPU_BASE(ptdev) (ptdev->hw->map.gpu_control_base)
+
 /**
  * struct panthor_gpu - GPU block management data.
  */
@@ -46,15 +49,15 @@ struct panthor_gpu {
 
 static void panthor_gpu_coherency_set(struct panthor_device *ptdev)
 {
-	gpu_write(ptdev, GPU_COHERENCY_PROTOCOL,
+	gpu_write(ptdev, GPU_BASE(ptdev) + GPU_COHERENCY_PROTOCOL,
 		ptdev->coherent ? GPU_COHERENCY_PROT_BIT(ACE_LITE) : GPU_COHERENCY_NONE);
 }
 
 static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status)
 {
 	if (status & GPU_IRQ_FAULT) {
-		u32 fault_status = gpu_read(ptdev, GPU_FAULT_STATUS);
-		u64 address = gpu_read64(ptdev, GPU_FAULT_ADDR_LO);
+		u32 fault_status = gpu_read(ptdev, GPU_BASE(ptdev) + GPU_FAULT_STATUS);
+		u64 address = gpu_read64(ptdev, GPU_BASE(ptdev) + GPU_FAULT_ADDR_LO);
 
 		drm_warn(&ptdev->base, "GPU Fault 0x%08x (%s) at 0x%016llx\n",
 			 fault_status, panthor_exception_name(ptdev, fault_status & 0xFF),
@@ -110,17 +113,14 @@ int panthor_gpu_init(struct panthor_device *ptdev)
 	init_waitqueue_head(&gpu->reqs_acked);
 	ptdev->gpu = gpu;
 
-	ret = panthor_props_init(ptdev);
-	if (ret)
-		return ret;
-
 	dma_set_max_seg_size(ptdev->base.dev, UINT_MAX);
 	ret = dma_set_mask_and_coherent(ptdev->base.dev,
 					DMA_BIT_MASK(ptdev->props->mmu_pa_bits));
 	if (ret)
 		return ret;
 
-	irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "gpu");
+	irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev),
+				      ptdev->hw->map.gpu_irq.name);
 	if (irq < 0)
 		return irq;
 
@@ -216,6 +216,12 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev,
 	return 0;
 }
 
+int panthor_gpu_l2_power_off(struct panthor_device *ptdev)
+{
+	return panthor_gpu_power_off(ptdev, L2, ptdev->gpu_info.l2_present,
+				     20000);
+}
+
 /**
  * panthor_gpu_l2_power_on() - Power-on the L2-cache
  * @ptdev: Device.
@@ -264,7 +270,7 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 	if (!drm_WARN_ON(&ptdev->base,
 			 ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
 		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
-		gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
+		gpu_write(ptdev, GPU_BASE(ptdev) + GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
 	}
 	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
 
@@ -272,8 +278,10 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
 				msecs_to_jiffies(100))) {
 		spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
-		if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 &&
-		    !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED))
+		if ((ptdev->gpu->pending_reqs &
+		     GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 &&
+		    !(gpu_read(ptdev, GPU_BASE(ptdev) + GPU_INT_RAWSTAT) &
+		      GPU_IRQ_CLEAN_CACHES_COMPLETED))
 			timedout = true;
 		else
 			ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
@@ -303,8 +311,8 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
 	if (!drm_WARN_ON(&ptdev->base,
 			 ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
 		ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
-		gpu_write(ptdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
-		gpu_write(ptdev, GPU_CMD, GPU_SOFT_RESET);
+		gpu_write(ptdev, GPU_BASE(ptdev) + GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
+		gpu_write(ptdev, GPU_BASE(ptdev) + GPU_CMD, GPU_SOFT_RESET);
 	}
 	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
 
@@ -313,7 +321,7 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
 				msecs_to_jiffies(100))) {
 		spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
 		if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
-		    !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
+		    !(gpu_read(ptdev, GPU_BASE(ptdev) + GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
 			timedout = true;
 		else
 			ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
@@ -341,7 +349,7 @@ void panthor_gpu_suspend(struct panthor_device *ptdev)
 	if (!ptdev->reset.fast)
 		panthor_gpu_soft_reset(ptdev);
 	else
-		panthor_gpu_power_off(ptdev, L2, 1, 20000);
+		ptdev->hw->ops.l2_power_off(ptdev);
 
 	panthor_gpu_irq_suspend(&ptdev->gpu->irq);
 }
@@ -356,7 +364,7 @@ void panthor_gpu_suspend(struct panthor_device *ptdev)
 void panthor_gpu_resume(struct panthor_device *ptdev)
 {
 	panthor_gpu_irq_resume(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK);
-	panthor_gpu_l2_power_on(ptdev);
+	ptdev->hw->ops.l2_power_on(ptdev);
 }
 
 /**
@@ -367,7 +375,7 @@ void panthor_gpu_resume(struct panthor_device *ptdev)
  */
 u64 panthor_gpu_read_timestamp(struct panthor_device *ptdev)
 {
-	return gpu_read64_sync(ptdev, GPU_TIMESTAMP_LO);
+	return gpu_read64_sync(ptdev, GPU_BASE(ptdev) + GPU_TIMESTAMP_LO);
 }
 
 /**
@@ -378,5 +386,5 @@ u64 panthor_gpu_read_timestamp(struct panthor_device *ptdev)
  */
 u64 panthor_gpu_read_timestamp_offset(struct panthor_device *ptdev)
 {
-	return gpu_read64(ptdev, GPU_TIMESTAMP_OFFSET_LO);
+	return gpu_read64(ptdev, GPU_BASE(ptdev) + GPU_TIMESTAMP_OFFSET_LO);
 }
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/panthor/panthor_gpu.h
index 7f6133a66127..887075a7b4d6 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.h
+++ b/drivers/gpu/drm/panthor/panthor_gpu.h
@@ -46,6 +46,7 @@ int panthor_gpu_block_power_off(struct panthor_device *ptdev,
 				   type ## _PWRTRANS_LO, \
 				   mask, timeout_us)
 
+int panthor_gpu_l2_power_off(struct panthor_device *ptdev);
 int panthor_gpu_l2_power_on(struct panthor_device *ptdev);
 int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 			     u32 l2, u32 lsc, u32 other);
diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
new file mode 100644
index 000000000000..0fb3adc093bc
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/* Copyright 2024 ARM Limited. All rights reserved. */
+
+#include <linux/types.h>
+
+#include <drm/drm_managed.h>
+
+#include "panthor_device.h"
+#include "panthor_gpu.h"
+#include "panthor_hw.h"
+#include "panthor_props.h"
+#include "panthor_regs.h"
+
+enum {
+	PANTHOR_ARCH_10_8 = 0,
+	PANTHOR_ARCH_COUNT
+};
+
+static struct panthor_hw panthor_hw_devices[] = {
+	[PANTHOR_ARCH_10_8] = {
+		.arch_id = GPU_ARCH_ID_MAKE(10, 8, 0),
+		.arch_mask = GPU_ARCH_ID_MAKE(0xFF, 0, 0),
+		.map = {
+			.mmu_as_base = ARCH_10_8_MMU_AS_BASE,
+			.mmu_as_stride = ARCH_10_8_MMU_AS_STRIDE,
+			.mcu_control_base = ARCH_10_8_MCU_CONTROL_BASE,
+			.gpu_control_base = ARCH_10_8_GPU_CONTROL_BASE,
+			.gpu_irq = {
+				.name = "gpu",
+				.base = ARCH_10_8_GPU_CONTROL_BASE,
+			},
+			.job_irq = {
+				.name = "job",
+				.base = JOB_CONTROL_BASE,
+			},
+			.mmu_irq = {
+				.name = "mmu",
+				.base = MMU_CONTROL_BASE,
+			}
+		},
+		.ops = {
+			.soft_reset = panthor_gpu_soft_reset,
+			.l2_power_off = panthor_gpu_l2_power_off,
+			.l2_power_on = panthor_gpu_l2_power_on,
+		}
+	},
+};
+
+static int bind_hw_device(struct panthor_device *ptdev)
+{
+	struct panthor_gpu_id_props *gpu_id = &ptdev->props->gpu_id;
+	struct panthor_hw *hdev = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(panthor_hw_devices); i++) {
+		u32 mask = panthor_hw_devices[i].arch_mask;
+		u32 arch_id = panthor_hw_devices[i].arch_id;
+
+		if ((gpu_id->arch_id & mask) == (arch_id & mask)) {
+			hdev = &panthor_hw_devices[i];
+			break;
+		}
+	}
+
+	if (!hdev)
+		return -ENODEV;
+
+	ptdev->hw = hdev;
+
+	return 0;
+}
+
+int panthor_hw_init(struct panthor_device *ptdev)
+{
+	int err;
+
+	err = panthor_props_init(ptdev);
+	if (err)
+		return err;
+
+	err = bind_hw_device(ptdev);
+	if (err)
+		return err;
+
+	panthor_props_load(ptdev);
+
+	return 0;
+}
+
+bool panthor_hw_supports(struct panthor_device *ptdev,
+			 enum panthor_hw_feature feature)
+{
+	return test_bit(feature, ptdev->hw->features);
+}
diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
new file mode 100644
index 000000000000..3409083d09d0
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2024 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_HW_H__
+#define __PANTHOR_HW_H__
+
+struct panthor_device;
+
+/**
+ * enum panthor_hw_feature - Bit position of each HW feature
+ *
+ * Used to define GPU specific features based on the GPU architecture ID.
+ * New feature flags will be added with support for newer GPU architectures.
+ */
+enum panthor_hw_feature {
+	PANTHOR_HW_FEATURES_END
+};
+
+struct panthor_hw_irq_regmap {
+	/** @name:  IRQ name in devicetree */
+	const char *name;
+
+	/** @base: Base address of IRQ register block */
+	const u64 base;
+};
+
+/**
+ * struct panthor_hw_regmap - Register offsets for specific register blocks
+ */
+struct panthor_hw_regmap {
+	/** @mmu_as_base: Base address of MMU address space 0 */
+	const u64 mmu_as_base;
+
+	/** @mmu_as_stride: Address offset between subsequent MMU address spaces */
+	const u64 mmu_as_stride;
+
+	/** @mcu_control_base: Base address of MCU_CONTROL */
+	const u64 mcu_control_base;
+
+	/** @gpu_control_base: Base address of GPU_CONTROL */
+	const u64 gpu_control_base;
+
+	/** @gpu_irq: GPU IRQ regmap */
+	const struct panthor_hw_irq_regmap gpu_irq;
+
+	/** @job_irq: JOB IRQ regmap */
+	const struct panthor_hw_irq_regmap job_irq;
+
+	/** @mmu_irq: MMU IRQ regmap */
+	const struct panthor_hw_irq_regmap mmu_irq;
+};
+
+/**
+ * struct panthor_hw_ops - HW operations that are specific to a GPU
+ */
+struct panthor_hw_ops {
+	/** @soft_reset: Soft reset function pointer */
+	int (*soft_reset)(struct panthor_device *ptdev);
+
+	/** @l2_power_off: L2 power off function pointer */
+	int (*l2_power_off)(struct panthor_device *ptdev);
+
+	/** @l2_power_on: L2 power on function pointer */
+	int (*l2_power_on)(struct panthor_device *ptdev);
+};
+
+/**
+ * struct panthor_hw - GPU specific register mapping and functions
+ */
+struct panthor_hw {
+	/** @arch_id: Architecture id to match against */
+	u32 arch_id;
+
+	/** @arch_mask: Mask for architecture id comparison */
+	u32 arch_mask;
+
+	/** @features: Bitmap containing panthor_hw_feature */
+	DECLARE_BITMAP(features, PANTHOR_HW_FEATURES_END);
+
+	/** @map: Panthor regmap */
+	struct panthor_hw_regmap map;
+
+	/** @ops: Panthor HW specific operations */
+	struct panthor_hw_ops ops;
+};
+
+int panthor_hw_init(struct panthor_device *ptdev);
+
+bool panthor_hw_supports(struct panthor_device *ptdev,
+			 enum panthor_hw_feature feature);
+
+#endif /* __PANTHOR_HW_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 2b6d147a2f0d..8a190dd2e06c 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -30,12 +30,17 @@
 #include "panthor_device.h"
 #include "panthor_gem.h"
 #include "panthor_heap.h"
+#include "panthor_hw.h"
 #include "panthor_mmu.h"
 #include "panthor_props.h"
 #include "panthor_regs.h"
 #include "panthor_sched.h"
 
 #define MAX_AS_SLOTS			32
+#define MMU_AS(ptdev, as) \
+	(ptdev->hw->map.mmu_as_base + ((as) * ptdev->hw->map.mmu_as_stride))
+
+#define MMU_BASE(ptdev) (ptdev->hw->map.mmu_irq.base)
 
 struct panthor_vm;
 
@@ -510,9 +515,9 @@ static int wait_ready(struct panthor_device *ptdev, u32 as_nr)
 	/* Wait for the MMU status to indicate there is no active command, in
 	 * case one is pending.
 	 */
-	ret = gpu_read_relaxed_poll_timeout_atomic(ptdev, AS_STATUS(as_nr), val,
-						   !(val & AS_STATUS_AS_ACTIVE),
-						   10, 100000);
+	ret = gpu_read_relaxed_poll_timeout_atomic(
+		ptdev, MMU_AS(ptdev, as_nr) + AS_STATUS, val,
+		!(val & AS_STATUS_AS_ACTIVE), 10, 100000);
 
 	if (ret) {
 		panthor_device_schedule_reset(ptdev);
@@ -529,7 +534,7 @@ static int write_cmd(struct panthor_device *ptdev, u32 as_nr, u32 cmd)
 	/* write AS_COMMAND when MMU is ready to accept another command */
 	status = wait_ready(ptdev, as_nr);
 	if (!status)
-		gpu_write(ptdev, AS_COMMAND(as_nr), cmd);
+		gpu_write(ptdev, MMU_AS(ptdev, as_nr) + AS_COMMAND, cmd);
 
 	return status;
 }
@@ -564,7 +569,7 @@ static void lock_region(struct panthor_device *ptdev, u32 as_nr,
 	region = region_width | region_start;
 
 	/* Lock the region that needs to be updated */
-	gpu_write64(ptdev, AS_LOCKADDR_LO(as_nr), region);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_LOCKADDR_LO, region);
 	write_cmd(ptdev, as_nr, AS_COMMAND_LOCK);
 }
 
@@ -614,9 +619,9 @@ static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr,
 	if (ret)
 		return ret;
 
-	gpu_write64(ptdev, AS_TRANSTAB_LO(as_nr), transtab);
-	gpu_write64(ptdev, AS_MEMATTR_LO(as_nr), memattr);
-	gpu_write64(ptdev, AS_TRANSCFG_LO(as_nr), transcfg);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_TRANSTAB_LO, transtab);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_MEMATTR_LO, memattr);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_TRANSCFG_LO, transcfg);
 
 	return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE);
 }
@@ -629,9 +634,9 @@ static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr)
 	if (ret)
 		return ret;
 
-	gpu_write64(ptdev, AS_TRANSTAB_LO(as_nr), 0);
-	gpu_write64(ptdev, AS_MEMATTR_LO(as_nr), 0);
-	gpu_write64(ptdev, AS_TRANSCFG_LO(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_TRANSTAB_LO, 0);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_MEMATTR_LO, 0);
+	gpu_write64(ptdev, MMU_AS(ptdev, as_nr) + AS_TRANSCFG_LO, AS_TRANSCFG_ADRMODE_UNMAPPED);
 
 	return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE);
 }
@@ -767,9 +772,10 @@ int panthor_vm_active(struct panthor_vm *vm)
 	 * before enabling the AS.
 	 */
 	if (ptdev->mmu->as.faulty_mask & panthor_mmu_as_fault_mask(ptdev, as)) {
-		gpu_write(ptdev, MMU_INT_CLEAR, panthor_mmu_as_fault_mask(ptdev, as));
+		gpu_write(ptdev, MMU_BASE(ptdev) + MMU_INT_CLEAR,
+			  panthor_mmu_as_fault_mask(ptdev, as));
 		ptdev->mmu->as.faulty_mask &= ~panthor_mmu_as_fault_mask(ptdev, as);
-		gpu_write(ptdev, MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask);
+		gpu_write(ptdev, MMU_BASE(ptdev) + MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask);
 	}
 
 	ret = panthor_mmu_as_enable(vm->ptdev, vm->as.id, transtab, transcfg, vm->memattr);
@@ -1664,8 +1670,8 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
 		u32 access_type;
 		u32 source_id;
 
-		fault_status = gpu_read(ptdev, AS_FAULTSTATUS(as));
-		addr = gpu_read64(ptdev, AS_FAULTADDRESS_LO(as));
+		fault_status = gpu_read(ptdev, MMU_AS(ptdev, as) + AS_FAULTSTATUS);
+		addr = gpu_read64(ptdev, MMU_AS(ptdev, as) + AS_FAULTADDRESS_LO);
 
 		/* decode the fault status */
 		exception_type = fault_status & 0xFF;
@@ -1697,7 +1703,7 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status)
 		 * re-enabled.
 		 */
 		ptdev->mmu->irq.mask = new_int_mask;
-		gpu_write(ptdev, MMU_INT_MASK, new_int_mask);
+		gpu_write(ptdev, MMU_BASE(ptdev) + MMU_INT_MASK, new_int_mask);
 
 		if (ptdev->mmu->as.slots[as].vm)
 			ptdev->mmu->as.slots[as].vm->unhandled_fault = true;
@@ -2707,7 +2713,8 @@ int panthor_mmu_init(struct panthor_device *ptdev)
 
 	ptdev->mmu = mmu;
 
-	irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "mmu");
+	irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev),
+				      ptdev->hw->map.mmu_irq.name);
 	if (irq <= 0)
 		return -ENODEV;
 
diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h
index bad172b8af82..9f22c16e5dac 100644
--- a/drivers/gpu/drm/panthor/panthor_regs.h
+++ b/drivers/gpu/drm/panthor/panthor_regs.h
@@ -12,7 +12,6 @@
 
 #include <linux/iopoll.h>
 
-/* GX10 registers */
 #define GPU_ID						0x0
 #define   GPU_ARCH_MAJOR(x)				((x) >> 28)
 #define   GPU_ARCH_MINOR(x)				(((x) & GENMASK(27, 24)) >> 24)
@@ -42,6 +41,8 @@
 #define GPU_AS_PRESENT					0x18
 #define GPU_CSF_ID					0x1C
 
+#define ARCH_10_8_GPU_CONTROL_BASE			0x0
+
 #define GPU_INT_RAWSTAT					0x20
 #define GPU_INT_CLEAR					0x24
 #define GPU_INT_MASK					0x28
@@ -145,41 +146,46 @@
 #define   GPU_COHERENCY_ACE_LITE			1
 #define   GPU_COHERENCY_NONE				31
 
-#define MCU_CONTROL					0x700
+#define ARCH_10_8_MCU_CONTROL_BASE			0x700
+
+#define MCU_CONTROL					0x0
 #define MCU_CONTROL_ENABLE				1
 #define MCU_CONTROL_AUTO				2
 #define MCU_CONTROL_DISABLE				0
 
-#define MCU_STATUS					0x704
+#define MCU_STATUS					0x4
 #define MCU_STATUS_DISABLED				0
 #define MCU_STATUS_ENABLED				1
 #define MCU_STATUS_HALT					2
 #define MCU_STATUS_FATAL				3
 
 /* Job Control regs */
-#define JOB_INT_RAWSTAT					0x1000
-#define JOB_INT_CLEAR					0x1004
-#define JOB_INT_MASK					0x1008
-#define JOB_INT_STAT					0x100c
+#define JOB_CONTROL_BASE				0x1000
+
+#define JOB_INT_RAWSTAT					0x0
+#define JOB_INT_CLEAR					0x4
+#define JOB_INT_MASK					0x8
+#define JOB_INT_STAT					0xc
 #define   JOB_INT_GLOBAL_IF				BIT(31)
 #define   JOB_INT_CSG_IF(x)				BIT(x)
 
 /* MMU regs */
-#define MMU_INT_RAWSTAT					0x2000
-#define MMU_INT_CLEAR					0x2004
-#define MMU_INT_MASK					0x2008
-#define MMU_INT_STAT					0x200c
+#define MMU_CONTROL_BASE				0x2000
+
+#define MMU_INT_RAWSTAT					0x0
+#define MMU_INT_CLEAR					0x4
+#define MMU_INT_MASK					0x8
+#define MMU_INT_STAT					0xc
 
 /* AS_COMMAND register commands */
 
-#define MMU_BASE					0x2400
-#define MMU_AS_SHIFT					6
-#define MMU_AS(as)					(MMU_BASE + ((as) << MMU_AS_SHIFT))
+#define ARCH_10_8_MMU_AS_BASE				0x2400
+#define ARCH_10_8_MMU_AS_STRIDE				0x40
 
-#define AS_TRANSTAB_LO(as)				(MMU_AS(as) + 0x0)
-#define AS_TRANSTAB_HI(as)				(MMU_AS(as) + 0x4)
-#define AS_MEMATTR_LO(as)				(MMU_AS(as) + 0x8)
-#define AS_MEMATTR_HI(as)				(MMU_AS(as) + 0xC)
+#define AS_TRANSTAB_LO					0x0
+#define AS_TRANSTAB_HI					0x4
+#define AS_MEMATTR_LO					0x8
+#define AS_MEMATTR_HI					0xC
 #define   AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL		(2 << 2)
 #define   AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r)	((3 << 2) | \
 							 ((w) ? BIT(0) : 0) | \
@@ -191,9 +197,9 @@
 #define   AS_MEMATTR_AARCH64_INNER_OUTER_NC		(1 << 6)
 #define   AS_MEMATTR_AARCH64_INNER_OUTER_WB		(2 << 6)
 #define   AS_MEMATTR_AARCH64_FAULT			(3 << 6)
-#define AS_LOCKADDR_LO(as)				(MMU_AS(as) + 0x10)
-#define AS_LOCKADDR_HI(as)				(MMU_AS(as) + 0x14)
-#define AS_COMMAND(as)					(MMU_AS(as) + 0x18)
+#define AS_LOCKADDR_LO					0x10
+#define AS_LOCKADDR_HI					0x14
+#define AS_COMMAND					0x18
 #define   AS_COMMAND_NOP				0
 #define   AS_COMMAND_UPDATE				1
 #define   AS_COMMAND_LOCK				2
@@ -201,18 +207,18 @@
 #define   AS_COMMAND_FLUSH_PT				4
 #define   AS_COMMAND_FLUSH_MEM				5
 #define   AS_LOCK_REGION_MIN_SIZE			(1ULL << 15)
-#define AS_FAULTSTATUS(as)				(MMU_AS(as) + 0x1C)
+#define AS_FAULTSTATUS					0x1C
 #define  AS_FAULTSTATUS_ACCESS_TYPE_MASK		(0x3 << 8)
 #define  AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC		(0x0 << 8)
 #define  AS_FAULTSTATUS_ACCESS_TYPE_EX			(0x1 << 8)
 #define  AS_FAULTSTATUS_ACCESS_TYPE_READ		(0x2 << 8)
 #define  AS_FAULTSTATUS_ACCESS_TYPE_WRITE		(0x3 << 8)
-#define AS_FAULTADDRESS_LO(as)				(MMU_AS(as) + 0x20)
-#define AS_FAULTADDRESS_HI(as)				(MMU_AS(as) + 0x24)
-#define AS_STATUS(as)					(MMU_AS(as) + 0x28)
+#define AS_FAULTADDRESS_LO				0x20
+#define AS_FAULTADDRESS_HI				0x24
+#define AS_STATUS					0x28
 #define   AS_STATUS_AS_ACTIVE				BIT(0)
-#define AS_TRANSCFG_LO(as)				(MMU_AS(as) + 0x30)
-#define AS_TRANSCFG_HI(as)				(MMU_AS(as) + 0x34)
+#define AS_TRANSCFG_LO					0x30
+#define AS_TRANSCFG_HI					0x34
 #define   AS_TRANSCFG_ADRMODE_UNMAPPED			(1 << 0)
 #define   AS_TRANSCFG_ADRMODE_IDENTITY			(2 << 0)
 #define   AS_TRANSCFG_ADRMODE_AARCH64_4K		(6 << 0)
@@ -230,8 +236,6 @@
 #define   AS_TRANSCFG_DISABLE_AF_FAULT			BIT(34)
 #define   AS_TRANSCFG_WXN				BIT(35)
 #define   AS_TRANSCFG_XREADABLE				BIT(36)
-#define AS_FAULTEXTRA_LO(as)				(MMU_AS(as) + 0x38)
-#define AS_FAULTEXTRA_HI(as)				(MMU_AS(as) + 0x3C)
 
 #define CSF_GPU_LATEST_FLUSH_ID				0x10000
 
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 209fd9576969..0c420e8c0acb 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -3838,6 +3838,7 @@ int panthor_sched_init(struct panthor_device *ptdev)
 			ptdev->props->mmu_as_count);
 		return -EINVAL;
 	}
+	gpu_as_count = ptdev->props->mmu_as_count - 1;
 
 	sched->ptdev = ptdev;
 	sched->sb_slot_count = CS_FEATURES_SCOREBOARDS(cs_iface->control->features);
