* [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs
@ 2025-10-27 16:13 Karunika Choo
2025-10-27 16:13 ` [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
` (8 more replies)
0 siblings, 9 replies; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
This patch series extends the Panthor driver with basic support for
Mali-G1 GPUs.
The v14 architecture introduces several hardware and register-level
changes compared to prior GPUs. This series adds the necessary
architecture-specific support infrastructure, power control and reset
handling for Mali-G1 GPUs.
Patch Breakdown:
[Patch 1-2]: Refactor panthor_hw to introduce architecture-specific
hooks and abstractions to support the v14 architecture.
These patches introduce architecture-specific HW binding
for function pointers.
[Patch 3-5]: Adds basic L2 power on/off and soft reset support for the
PWR_CONTROL block introduced in v14.
[Patch 6]: Update MCU halt and warm boot operations to reflect the
GLB_REQ.STATE changes in v14. This ensures that the MCU is
properly halted and the correct operations are performed
on warm boot depending on the FW version.
[Patch 7]: Align endpoint_req with changes introduced in v14, where
the register is widened to 64-bit and shifed down by
4-bytes. This patch adds the necessary infrastructure to
discern the correct endpoint_req register to use.
[Patch 8]: Enables Mali-G1 support on Panthor by adding HW bindings
for v14 architecture, product names and path to FW binary.
v3:
* Updated include logic to enable static inline functions in
panthor_hw.h for function pointers and feature checks.
* Fixed missed replacement of CSF_IFACE_VERSION check with
panthor_fw_has_glb_state() check.
* Link to v2: https://lore.kernel.org/all/20251024202117.3241292-1-karunika.choo@arm.com/
v2:
* Merged GPU_ID refactoring patch with the arch-specific panthor_hw
binding patch (formerly PATCH 01/10 and PATCH 02/10).
* Dropped panthor_hw feature bitmap patch in favor of functions that
performs the relevant architecture version checks.
* Fixed kernel test bot warnings.
* Replaced function pointer accessor MACROs with static inline
functions.
* Refined power control logic, removed unnecessary checks and redundant
stubs.
* Replaced explicit CSG_IFACE_VERSION checks with functions describing
the feature being checked for.
* General readability improvements, more consistent error handling,
behaviour clarifications, and formatting fixes.
* Link to v1: https://lore.kernel.org/all/20251014094337.1009601-1-karunika.choo@arm.com/
Karunika Choo (8):
drm/panthor: Add arch-specific panthor_hw binding
drm/panthor: Add architecture-specific function operations
drm/panthor: Introduce panthor_pwr API and power control framework
drm/panthor: Implement L2 power on/off via PWR_CONTROL
drm/panthor: Implement soft reset via PWR_CONTROL
drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
drm/panthor: Support 64-bit endpoint_req register for Mali-G1
drm/panthor: Add support for Mali-G1 GPUs
drivers/gpu/drm/panthor/Makefile | 1 +
drivers/gpu/drm/panthor/panthor_device.c | 18 +-
drivers/gpu/drm/panthor/panthor_device.h | 7 +
drivers/gpu/drm/panthor/panthor_fw.c | 131 +++++-
drivers/gpu/drm/panthor/panthor_fw.h | 32 +-
drivers/gpu/drm/panthor/panthor_gpu.c | 12 +-
drivers/gpu/drm/panthor/panthor_gpu.h | 1 +
drivers/gpu/drm/panthor/panthor_hw.c | 108 ++++-
drivers/gpu/drm/panthor/panthor_hw.h | 47 +-
drivers/gpu/drm/panthor/panthor_pwr.c | 548 +++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_pwr.h | 23 +
drivers/gpu/drm/panthor/panthor_regs.h | 79 ++++
drivers/gpu/drm/panthor/panthor_sched.c | 21 +-
13 files changed, 987 insertions(+), 41 deletions(-)
create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.c
create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.h
--
2.49.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-10-28 16:16 ` Liviu Dudau
2025-10-27 16:13 ` [PATCH v3 2/8] drm/panthor: Add architecture-specific function operations Karunika Choo
` (7 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
This patch adds the framework for binding to a specific panthor_hw
structure based on the architecture major value parsed from the GPU_ID
register. This is in preparation of enabling architecture-specific
behaviours based on GPU_ID. As such, it also splits the GPU_ID register
read operation into its own helper function.
This framework allows a single panthor_hw structure to be shared across
multiple architectures should there be minimal changes between them via
the arch_min and arch_max field of the panthor_hw_entry structure,
instead of duplicating the structure across multiple architectures.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v2:
* merged GPU_ID refactoring patch with the arch-specific panthor_hw
binding patch (PATCH 01/10 and PATCH 02/10 in v1).
---
drivers/gpu/drm/panthor/panthor_device.h | 4 ++
drivers/gpu/drm/panthor/panthor_hw.c | 65 +++++++++++++++++++++++-
drivers/gpu/drm/panthor/panthor_hw.h | 6 +++
3 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index a764111359d2..1457c1255f1f 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -26,6 +26,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_fw;
@@ -122,6 +123,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;
diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
index 4f2858114e5e..b6e7401327c3 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -8,6 +8,28 @@
#define GPU_PROD_ID_MAKE(arch_major, prod_major) \
(((arch_major) << 24) | (prod_major))
+/** struct panthor_hw_entry - HW arch major to panthor_hw binding entry */
+struct panthor_hw_entry {
+ /** @arch_min: Minimum supported architecture major value (inclusive) */
+ u8 arch_min;
+
+ /** @arch_max: Maximum supported architecture major value (inclusive) */
+ u8 arch_max;
+
+ /** @hwdev: Pointer to panthor_hw structure */
+ struct panthor_hw *hwdev;
+};
+
+static struct panthor_hw panthor_hw_arch_v10 = {};
+
+static struct panthor_hw_entry panthor_hw_match[] = {
+ {
+ .arch_min = 10,
+ .arch_max = 13,
+ .hwdev = &panthor_hw_arch_v10,
+ },
+};
+
static char *get_gpu_model_name(struct panthor_device *ptdev)
{
const u32 gpu_id = ptdev->gpu_info.gpu_id;
@@ -62,7 +84,6 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
{
unsigned int i;
- ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID);
ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID);
ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES);
@@ -117,8 +138,50 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
ptdev->gpu_info.tiler_present);
}
+static int panthor_hw_bind_device(struct panthor_device *ptdev)
+{
+ struct panthor_hw *hdev = NULL;
+ const u32 arch_major = GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id);
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(panthor_hw_match); i++) {
+ struct panthor_hw_entry *entry = &panthor_hw_match[i];
+
+ if (arch_major >= entry->arch_min && arch_major <= entry->arch_max) {
+ hdev = entry->hwdev;
+ break;
+ }
+ }
+
+ if (!hdev)
+ return -EOPNOTSUPP;
+
+ ptdev->hw = hdev;
+
+ return 0;
+}
+
+static int panthor_hw_gpu_id_init(struct panthor_device *ptdev)
+{
+ ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
+ if (!ptdev->gpu_info.gpu_id)
+ return -ENXIO;
+
+ return 0;
+}
+
int panthor_hw_init(struct panthor_device *ptdev)
{
+ int ret = 0;
+
+ ret = panthor_hw_gpu_id_init(ptdev);
+ if (ret)
+ return ret;
+
+ ret = panthor_hw_bind_device(ptdev);
+ if (ret)
+ return ret;
+
panthor_hw_info_init(ptdev);
return 0;
diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
index 0af6acc6aa6a..39752de3e7ad 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -6,6 +6,12 @@
struct panthor_device;
+/**
+ * struct panthor_hw - GPU specific register mapping and functions
+ */
+struct panthor_hw {
+};
+
int panthor_hw_init(struct panthor_device *ptdev);
#endif /* __PANTHOR_HW_H__ */
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 2/8] drm/panthor: Add architecture-specific function operations
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-10-27 16:13 ` [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 9:48 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
` (6 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Introduce architecture-specific function pointers to support
architecture-dependent behaviours. This patch adds the following
function pointers and updates their usage accordingly:
- soft_reset
- l2_power_on
- l2_power_off
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v3:
* Reverted includes changes to align with the include behaviour of the
rest of the driver while enabling the definition of static inline
function pointer accessors.
* Moved the function pointer accessors from panthor_device.h to
panthor_hw.h
v2:
* Updated includes for panthor_hw.h to allow static inline function
pointer accessor functions instead of MACROs.
* updated l2_power_off function signature to void instead of returning
int as we have no way of handling a failure in this case.
---
drivers/gpu/drm/panthor/panthor_device.c | 4 +--
drivers/gpu/drm/panthor/panthor_device.h | 1 -
drivers/gpu/drm/panthor/panthor_fw.c | 5 ++--
drivers/gpu/drm/panthor/panthor_gpu.c | 12 ++++++--
drivers/gpu/drm/panthor/panthor_gpu.h | 1 +
drivers/gpu/drm/panthor/panthor_hw.c | 9 +++++-
drivers/gpu/drm/panthor/panthor_hw.h | 35 +++++++++++++++++++++++-
7 files changed, 57 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index 81df49880bd8..847dea458682 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -141,8 +141,8 @@ static void panthor_device_reset_work(struct work_struct *work)
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);
+ panthor_hw_soft_reset(ptdev);
+ panthor_hw_l2_power_on(ptdev);
panthor_mmu_post_reset(ptdev);
ret = panthor_fw_post_reset(ptdev);
atomic_set(&ptdev->reset.pending, 0);
diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index 1457c1255f1f..f8e37a24d081 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -26,7 +26,6 @@ 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_fw;
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 9bf06e55eaee..e6c39c70d348 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_regs.h"
#include "panthor_sched.h"
@@ -1184,7 +1185,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);
+ panthor_hw_l2_power_off(ptdev);
}
/**
@@ -1363,7 +1364,7 @@ int panthor_fw_init(struct panthor_device *ptdev)
return ret;
}
- ret = panthor_gpu_l2_power_on(ptdev);
+ ret = panthor_hw_l2_power_on(ptdev);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index db69449a5be0..63ed8c461796 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -18,6 +18,7 @@
#include "panthor_device.h"
#include "panthor_gpu.h"
+#include "panthor_hw.h"
#include "panthor_regs.h"
/**
@@ -218,6 +219,11 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev,
return 0;
}
+void panthor_gpu_l2_power_off(struct panthor_device *ptdev)
+{
+ panthor_gpu_power_off(ptdev, L2, ptdev->gpu_info.l2_present, 20000);
+}
+
/**
* panthor_gpu_l2_power_on() - Power-on the L2-cache
* @ptdev: Device.
@@ -344,9 +350,9 @@ void panthor_gpu_suspend(struct panthor_device *ptdev)
{
/* On a fast reset, simply power down the L2. */
if (!ptdev->reset.fast)
- panthor_gpu_soft_reset(ptdev);
+ panthor_hw_soft_reset(ptdev);
else
- panthor_gpu_power_off(ptdev, L2, 1, 20000);
+ panthor_hw_l2_power_off(ptdev);
panthor_gpu_irq_suspend(&ptdev->gpu->irq);
}
@@ -361,6 +367,6 @@ 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);
+ panthor_hw_l2_power_on(ptdev);
}
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/panthor/panthor_gpu.h
index 7c17a8c06858..12e66f48ced1 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, \
mask, timeout_us)
+void 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
index b6e7401327c3..ed0ebd53f4ba 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -2,6 +2,7 @@
/* Copyright 2025 ARM Limited. All rights reserved. */
#include "panthor_device.h"
+#include "panthor_gpu.h"
#include "panthor_hw.h"
#include "panthor_regs.h"
@@ -20,7 +21,13 @@ struct panthor_hw_entry {
struct panthor_hw *hwdev;
};
-static struct panthor_hw panthor_hw_arch_v10 = {};
+static struct panthor_hw panthor_hw_arch_v10 = {
+ .ops = {
+ .soft_reset = panthor_gpu_soft_reset,
+ .l2_power_off = panthor_gpu_l2_power_off,
+ .l2_power_on = panthor_gpu_l2_power_on,
+ },
+};
static struct panthor_hw_entry panthor_hw_match[] = {
{
diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
index 39752de3e7ad..64616caa6f05 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -4,14 +4,47 @@
#ifndef __PANTHOR_HW_H__
#define __PANTHOR_HW_H__
-struct panthor_device;
+#include "panthor_device.h"
+
+/**
+ * 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 */
+ void (*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 {
+ /** @features: Bitmap containing panthor_hw_feature */
+
+ /** @ops: Panthor HW specific operations */
+ struct panthor_hw_ops ops;
};
int panthor_hw_init(struct panthor_device *ptdev);
+static inline int panthor_hw_soft_reset(struct panthor_device *ptdev)
+{
+ return ptdev->hw->ops.soft_reset(ptdev);
+}
+
+static inline int panthor_hw_l2_power_on(struct panthor_device *ptdev)
+{
+ return ptdev->hw->ops.l2_power_on(ptdev);
+}
+
+static inline void panthor_hw_l2_power_off(struct panthor_device *ptdev)
+{
+ ptdev->hw->ops.l2_power_off(ptdev);
+}
+
#endif /* __PANTHOR_HW_H__ */
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-10-27 16:13 ` [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
2025-10-27 16:13 ` [PATCH v3 2/8] drm/panthor: Add architecture-specific function operations Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 10:07 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
` (5 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Add the new panthor_pwr module, which provides basic power control
management for Mali-G1 GPUs. The initial implementation includes
infrastructure for initializing the PWR_CONTROL block, requesting and
handling its IRQ, and checking for PWR_CONTROL support based on GPU
architecture.
The patch also integrates panthor_pwr with the device lifecycle (init,
suspend, resume, and unplug) through the new API functions. It also
registers the IRQ handler under the 'gpu' IRQ as the PWR_CONTROL block
is located within the GPU_CONTROL block.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v3:
* Turned panthor_hw_has_pwr_ctrl() into a static inline function.
v2:
* Removed stub functions.
* Updated BIT() definitions for 64-bit fields to use BIT_U64() to
address kernel test robot warnings for 32-bit systems.
* Moved GPU_FEATURES_RAY_TRAVERSAL definition to the next patch where
it is being used.
* Drop the use of feature bits in favour of a function that performs a
GPU_ARCH_MAJOR check instead.
---
drivers/gpu/drm/panthor/Makefile | 1 +
drivers/gpu/drm/panthor/panthor_device.c | 14 ++-
drivers/gpu/drm/panthor/panthor_device.h | 4 +
drivers/gpu/drm/panthor/panthor_hw.c | 1 -
drivers/gpu/drm/panthor/panthor_hw.h | 6 ++
drivers/gpu/drm/panthor/panthor_pwr.c | 120 +++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_pwr.h | 17 ++++
drivers/gpu/drm/panthor/panthor_regs.h | 78 +++++++++++++++
8 files changed, 239 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.c
create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.h
diff --git a/drivers/gpu/drm/panthor/Makefile b/drivers/gpu/drm/panthor/Makefile
index 02db21748c12..753a32c446df 100644
--- a/drivers/gpu/drm/panthor/Makefile
+++ b/drivers/gpu/drm/panthor/Makefile
@@ -10,6 +10,7 @@ panthor-y := \
panthor_heap.o \
panthor_hw.o \
panthor_mmu.o \
+ panthor_pwr.o \
panthor_sched.o
obj-$(CONFIG_DRM_PANTHOR) += panthor.o
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index 847dea458682..d3e16da0b24e 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -20,6 +20,7 @@
#include "panthor_gpu.h"
#include "panthor_hw.h"
#include "panthor_mmu.h"
+#include "panthor_pwr.h"
#include "panthor_regs.h"
#include "panthor_sched.h"
@@ -102,6 +103,7 @@ void panthor_device_unplug(struct panthor_device *ptdev)
panthor_fw_unplug(ptdev);
panthor_mmu_unplug(ptdev);
panthor_gpu_unplug(ptdev);
+ panthor_pwr_unplug(ptdev);
pm_runtime_dont_use_autosuspend(ptdev->base.dev);
pm_runtime_put_sync_suspend(ptdev->base.dev);
@@ -249,10 +251,14 @@ int panthor_device_init(struct panthor_device *ptdev)
if (ret)
goto err_rpm_put;
- ret = panthor_gpu_init(ptdev);
+ ret = panthor_pwr_init(ptdev);
if (ret)
goto err_rpm_put;
+ ret = panthor_gpu_init(ptdev);
+ if (ret)
+ goto err_unplug_pwr;
+
ret = panthor_gpu_coherency_init(ptdev);
if (ret)
goto err_unplug_gpu;
@@ -293,6 +299,9 @@ int panthor_device_init(struct panthor_device *ptdev)
err_unplug_gpu:
panthor_gpu_unplug(ptdev);
+err_unplug_pwr:
+ panthor_pwr_unplug(ptdev);
+
err_rpm_put:
pm_runtime_put_sync_suspend(ptdev->base.dev);
return ret;
@@ -446,6 +455,7 @@ static int panthor_device_resume_hw_components(struct panthor_device *ptdev)
{
int ret;
+ panthor_pwr_resume(ptdev);
panthor_gpu_resume(ptdev);
panthor_mmu_resume(ptdev);
@@ -455,6 +465,7 @@ static int panthor_device_resume_hw_components(struct panthor_device *ptdev)
panthor_mmu_suspend(ptdev);
panthor_gpu_suspend(ptdev);
+ panthor_pwr_suspend(ptdev);
return ret;
}
@@ -568,6 +579,7 @@ int panthor_device_suspend(struct device *dev)
panthor_fw_suspend(ptdev);
panthor_mmu_suspend(ptdev);
panthor_gpu_suspend(ptdev);
+ panthor_pwr_suspend(ptdev);
drm_dev_exit(cookie);
}
diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index f8e37a24d081..5afa9fdfbc31 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -30,6 +30,7 @@ struct panthor_job;
struct panthor_mmu;
struct panthor_fw;
struct panthor_perfcnt;
+struct panthor_pwr;
struct panthor_vm;
struct panthor_vm_pool;
@@ -125,6 +126,9 @@ struct panthor_device {
/** @hw: GPU-specific data. */
struct panthor_hw *hw;
+ /** @pwr: Power control management data. */
+ struct panthor_pwr *pwr;
+
/** @gpu: GPU management data. */
struct panthor_gpu *gpu;
diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
index ed0ebd53f4ba..1041201d83e5 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -4,7 +4,6 @@
#include "panthor_device.h"
#include "panthor_gpu.h"
#include "panthor_hw.h"
-#include "panthor_regs.h"
#define GPU_PROD_ID_MAKE(arch_major, prod_major) \
(((arch_major) << 24) | (prod_major))
diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
index 64616caa6f05..56c68c1e9c26 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -5,6 +5,7 @@
#define __PANTHOR_HW_H__
#include "panthor_device.h"
+#include "panthor_regs.h"
/**
* struct panthor_hw_ops - HW operations that are specific to a GPU
@@ -47,4 +48,9 @@ static inline void panthor_hw_l2_power_off(struct panthor_device *ptdev)
ptdev->hw->ops.l2_power_off(ptdev);
}
+static inline bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
+{
+ return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
+}
+
#endif /* __PANTHOR_HW_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
new file mode 100644
index 000000000000..da64fe006a8b
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_pwr.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+/* Copyright 2025 ARM Limited. All rights reserved. */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/wait.h>
+
+#include <drm/drm_managed.h>
+
+#include "panthor_device.h"
+#include "panthor_hw.h"
+#include "panthor_pwr.h"
+#include "panthor_regs.h"
+
+#define PWR_INTERRUPTS_MASK \
+ (PWR_IRQ_POWER_CHANGED_SINGLE | \
+ PWR_IRQ_POWER_CHANGED_ALL | \
+ PWR_IRQ_DELEGATION_CHANGED | \
+ PWR_IRQ_RESET_COMPLETED | \
+ PWR_IRQ_RETRACT_COMPLETED | \
+ PWR_IRQ_INSPECT_COMPLETED | \
+ PWR_IRQ_COMMAND_NOT_ALLOWED | \
+ PWR_IRQ_COMMAND_INVALID)
+
+/**
+ * struct panthor_pwr - PWR_CONTROL block management data.
+ */
+struct panthor_pwr {
+ /** @irq: PWR irq. */
+ struct panthor_irq irq;
+
+ /** @reqs_lock: Lock protecting access to pending_reqs. */
+ spinlock_t reqs_lock;
+
+ /** @pending_reqs: Pending PWR requests. */
+ u32 pending_reqs;
+
+ /** @reqs_acked: PWR request wait queue. */
+ wait_queue_head_t reqs_acked;
+};
+
+static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
+{
+ spin_lock(&ptdev->pwr->reqs_lock);
+ gpu_write(ptdev, PWR_INT_CLEAR, status);
+
+ if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED))
+ drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED");
+
+ if (unlikely(status & PWR_IRQ_COMMAND_INVALID))
+ drm_err(&ptdev->base, "PWR_IRQ: COMMAND_INVALID");
+
+ if (status & ptdev->pwr->pending_reqs) {
+ ptdev->pwr->pending_reqs &= ~status;
+ wake_up_all(&ptdev->pwr->reqs_acked);
+ }
+ spin_unlock(&ptdev->pwr->reqs_lock);
+}
+PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler);
+
+void panthor_pwr_unplug(struct panthor_device *ptdev)
+{
+ unsigned long flags;
+
+ if (!ptdev->pwr)
+ return;
+
+ /* Make sure the IRQ handler is not running after that point. */
+ panthor_pwr_irq_suspend(&ptdev->pwr->irq);
+
+ /* Wake-up all waiters. */
+ spin_lock_irqsave(&ptdev->pwr->reqs_lock, flags);
+ ptdev->pwr->pending_reqs = 0;
+ wake_up_all(&ptdev->pwr->reqs_acked);
+ spin_unlock_irqrestore(&ptdev->pwr->reqs_lock, flags);
+}
+
+int panthor_pwr_init(struct panthor_device *ptdev)
+{
+ struct panthor_pwr *pwr;
+ int err, irq;
+
+ if (!panthor_hw_has_pwr_ctrl(ptdev))
+ return 0;
+
+ pwr = drmm_kzalloc(&ptdev->base, sizeof(*pwr), GFP_KERNEL);
+ if (!pwr)
+ return -ENOMEM;
+
+ spin_lock_init(&pwr->reqs_lock);
+ init_waitqueue_head(&pwr->reqs_acked);
+ ptdev->pwr = pwr;
+
+ irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "gpu");
+ if (irq < 0)
+ return irq;
+
+ err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+void panthor_pwr_suspend(struct panthor_device *ptdev)
+{
+ if (!ptdev->pwr)
+ return;
+
+ panthor_pwr_irq_suspend(&ptdev->pwr->irq);
+}
+
+void panthor_pwr_resume(struct panthor_device *ptdev)
+{
+ if (!ptdev->pwr)
+ return;
+
+ panthor_pwr_irq_resume(&ptdev->pwr->irq, PWR_INTERRUPTS_MASK);
+}
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.h b/drivers/gpu/drm/panthor/panthor_pwr.h
new file mode 100644
index 000000000000..b325e5b7eba3
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_pwr.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 or MIT */
+/* Copyright 2025 ARM Limited. All rights reserved. */
+
+#ifndef __PANTHOR_PWR_H__
+#define __PANTHOR_PWR_H__
+
+struct panthor_device;
+
+void panthor_pwr_unplug(struct panthor_device *ptdev);
+
+int panthor_pwr_init(struct panthor_device *ptdev);
+
+void panthor_pwr_suspend(struct panthor_device *ptdev);
+
+void panthor_pwr_resume(struct panthor_device *ptdev);
+
+#endif /* __PANTHOR_PWR_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h
index 8bee76d01bf8..5469eec02178 100644
--- a/drivers/gpu/drm/panthor/panthor_regs.h
+++ b/drivers/gpu/drm/panthor/panthor_regs.h
@@ -205,4 +205,82 @@
#define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000))
#define CSF_GLB_DOORBELL_ID 0
+/* PWR Control registers */
+
+#define PWR_CONTROL_BASE 0x800
+#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x))
+
+#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0)
+#define PWR_INT_CLEAR PWR_CTRL_REG(0x4)
+#define PWR_INT_MASK PWR_CTRL_REG(0x8)
+#define PWR_INT_STAT PWR_CTRL_REG(0xc)
+#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0)
+#define PWR_IRQ_POWER_CHANGED_ALL BIT(1)
+#define PWR_IRQ_DELEGATION_CHANGED BIT(2)
+#define PWR_IRQ_RESET_COMPLETED BIT(3)
+#define PWR_IRQ_RETRACT_COMPLETED BIT(4)
+#define PWR_IRQ_INSPECT_COMPLETED BIT(5)
+#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30)
+#define PWR_IRQ_COMMAND_INVALID BIT(31)
+
+#define PWR_STATUS PWR_CTRL_REG(0x20)
+#define PWR_STATUS_ALLOW_L2 BIT_U64(0)
+#define PWR_STATUS_ALLOW_TILER BIT_U64(1)
+#define PWR_STATUS_ALLOW_SHADER BIT_U64(8)
+#define PWR_STATUS_ALLOW_BASE BIT_U64(14)
+#define PWR_STATUS_ALLOW_STACK BIT_U64(15)
+#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x)
+#define PWR_STATUS_DELEGATED_L2 BIT_U64(16)
+#define PWR_STATUS_DELEGATED_TILER BIT_U64(17)
+#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24)
+#define PWR_STATUS_DELEGATED_BASE BIT_U64(30)
+#define PWR_STATUS_DELEGATED_STACK BIT_U64(31)
+#define PWR_STATUS_DELEGATED_SHIFT 16
+#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT)
+#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33)
+#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34)
+#define PWR_STATUS_POWER_PENDING BIT_U64(41)
+#define PWR_STATUS_RESET_PENDING BIT_U64(42)
+#define PWR_STATUS_RETRACT_PENDING BIT_U64(43)
+#define PWR_STATUS_INSPECT_PENDING BIT_U64(44)
+
+#define PWR_COMMAND PWR_CTRL_REG(0x28)
+#define PWR_COMMAND_POWER_UP 0x10
+#define PWR_COMMAND_POWER_DOWN 0x11
+#define PWR_COMMAND_DELEGATE 0x20
+#define PWR_COMMAND_RETRACT 0x21
+#define PWR_COMMAND_RESET_SOFT 0x31
+#define PWR_COMMAND_RESET_FAST 0x32
+#define PWR_COMMAND_INSPECT 0xF0
+#define PWR_COMMAND_DOMAIN_L2 0
+#define PWR_COMMAND_DOMAIN_TILER 1
+#define PWR_COMMAND_DOMAIN_SHADER 8
+#define PWR_COMMAND_DOMAIN_BASE 14
+#define PWR_COMMAND_DOMAIN_STACK 15
+#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0)
+#define PWR_COMMAND_DEF(cmd, domain, subdomain) \
+ (((subdomain) << 16) | ((domain) << 8) | (cmd))
+
+#define PWR_CMDARG PWR_CTRL_REG(0x30)
+
+#define PWR_L2_PRESENT PWR_CTRL_REG(0x100)
+#define PWR_L2_READY PWR_CTRL_REG(0x108)
+#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110)
+#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118)
+#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140)
+#define PWR_TILER_READY PWR_CTRL_REG(0x148)
+#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150)
+#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158)
+#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200)
+#define PWR_SHADER_READY PWR_CTRL_REG(0x208)
+#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210)
+#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218)
+#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380)
+#define PWR_BASE_READY PWR_CTRL_REG(0x388)
+#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390)
+#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398)
+#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0)
+#define PWR_STACK_READY PWR_CTRL_REG(0x3c8)
+#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0)
+
#endif
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (2 preceding siblings ...)
2025-10-27 16:13 ` [PATCH v3 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 10:18 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 5/8] drm/panthor: Implement soft reset " Karunika Choo
` (4 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
This patch adds common helpers to issue power commands, poll
transitions, and validate domain state, then wires them into the L2
on/off paths.
The L2 power-on sequence now delegates control of the SHADER and TILER
domains to the MCU when allowed, while the L2 itself is never delegated.
On power-off, dependent domains beneath the L2 are checked, and if
necessary, retracted and powered down to maintain proper domain
ordering.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v2:
* Updated GENMASK to GENMASK_U64 to address kernel test robot warnings
for 32-bit systems.
* Removed panthor_pwr_read_status() in favour of a simple gpu_read64()
operation on the PWR_STATUS register.
* Renamed panthor_pwr_info_show() to panthor_pwr_debug_info_show() for
more clarity.
* Added additional WARN_ON for an invalid domain when requesting power
domain transition.
* Made panthor_pwr_domain_transition()'s expected val logic more
readable and clearer.
* Wait on domain power transition instead of failing the operation.
* Fixed inconsistent error return value vs kerneldoc.
* Removed confusing drm_dbg in delegate_domain() in favor of a comment.
* Add unwind to panthor_pwr_delegate_domains().
* Moved child domain handling logic from panthor_pwr_l2_power_off()
into panthor_pwr_domain_force_off().
* Added additional clarification regarding delegation and retraction of
power domains.
* Minor formatting and readability changes and remove unnecessary
checks.
---
drivers/gpu/drm/panthor/panthor_pwr.c | 378 +++++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_pwr.h | 4 +
drivers/gpu/drm/panthor/panthor_regs.h | 1 +
3 files changed, 383 insertions(+)
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
index da64fe006a8b..cd529660a276 100644
--- a/drivers/gpu/drm/panthor/panthor_pwr.c
+++ b/drivers/gpu/drm/panthor/panthor_pwr.c
@@ -23,6 +23,14 @@
PWR_IRQ_COMMAND_NOT_ALLOWED | \
PWR_IRQ_COMMAND_INVALID)
+#define PWR_ALL_CORES_MASK GENMASK_U64(63, 0)
+
+#define PWR_DOMAIN_MAX_BITS 16
+
+#define PWR_TRANSITION_TIMEOUT_US (2ULL * USEC_PER_SEC)
+
+#define PWR_RETRACT_TIMEOUT_US (2ULL * USEC_PER_MSEC)
+
/**
* struct panthor_pwr - PWR_CONTROL block management data.
*/
@@ -59,6 +67,323 @@ static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
}
PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler);
+static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args)
+{
+ if (args)
+ gpu_write64(ptdev, PWR_CMDARG, args);
+
+ gpu_write(ptdev, PWR_COMMAND, command);
+}
+
+static const char *get_domain_name(u8 domain)
+{
+ switch (domain) {
+ case PWR_COMMAND_DOMAIN_L2:
+ return "L2";
+ case PWR_COMMAND_DOMAIN_TILER:
+ return "Tiler";
+ case PWR_COMMAND_DOMAIN_SHADER:
+ return "Shader";
+ case PWR_COMMAND_DOMAIN_BASE:
+ return "Base";
+ case PWR_COMMAND_DOMAIN_STACK:
+ return "Stack";
+ }
+ return "Unknown";
+}
+
+static u32 get_domain_base(u8 domain)
+{
+ switch (domain) {
+ case PWR_COMMAND_DOMAIN_L2:
+ return PWR_L2_PRESENT;
+ case PWR_COMMAND_DOMAIN_TILER:
+ return PWR_TILER_PRESENT;
+ case PWR_COMMAND_DOMAIN_SHADER:
+ return PWR_SHADER_PRESENT;
+ case PWR_COMMAND_DOMAIN_BASE:
+ return PWR_BASE_PRESENT;
+ case PWR_COMMAND_DOMAIN_STACK:
+ return PWR_STACK_PRESENT;
+ }
+ return 0;
+}
+
+static u32 get_domain_ready_reg(u32 domain)
+{
+ return get_domain_base(domain) + (PWR_L2_READY - PWR_L2_PRESENT);
+}
+
+static u32 get_domain_pwrtrans_reg(u32 domain)
+{
+ return get_domain_base(domain) + (PWR_L2_PWRTRANS - PWR_L2_PRESENT);
+}
+
+static bool is_valid_domain(u32 domain)
+{
+ return get_domain_base(domain) != 0;
+}
+
+static bool has_rtu(struct panthor_device *ptdev)
+{
+ return ptdev->gpu_info.gpu_features & GPU_FEATURES_RAY_TRAVERSAL;
+}
+
+static u8 get_domain_subdomain(struct panthor_device *ptdev, u32 domain)
+{
+ if ((domain == PWR_COMMAND_DOMAIN_SHADER) && has_rtu(ptdev))
+ return PWR_COMMAND_SUBDOMAIN_RTU;
+
+ return 0;
+}
+
+static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 domain,
+ u32 timeout_us)
+{
+ u32 pwrtrans_reg = get_domain_pwrtrans_reg(domain);
+ u64 val;
+ int ret = 0;
+
+ ret = gpu_read64_poll_timeout(ptdev, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100,
+ timeout_us);
+ if (ret) {
+ drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)",
+ get_domain_name(domain), val);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void panthor_pwr_debug_info_show(struct panthor_device *ptdev)
+{
+ drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev, GPU_FEATURES));
+ drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev, PWR_STATUS));
+ drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_L2_PRESENT));
+ drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_L2_PWRTRANS));
+ drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev, PWR_L2_READY));
+ drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PRESENT));
+ drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PWRTRANS));
+ drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev, PWR_TILER_READY));
+ drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PRESENT));
+ drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PWRTRANS));
+ drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_READY));
+}
+
+static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain,
+ u64 mask, u32 timeout_us)
+{
+ u32 ready_reg = get_domain_ready_reg(domain);
+ u32 pwr_cmd = PWR_COMMAND_DEF(cmd, domain, get_domain_subdomain(ptdev, domain));
+ u64 expected_val = 0;
+ u64 val;
+ int ret = 0;
+
+ if (drm_WARN_ON(&ptdev->base, !is_valid_domain(domain)))
+ return -EINVAL;
+
+ switch (cmd) {
+ case PWR_COMMAND_POWER_DOWN:
+ expected_val = 0;
+ break;
+ case PWR_COMMAND_POWER_UP:
+ expected_val = mask;
+ break;
+ default:
+ drm_err(&ptdev->base, "Invalid power domain transition command (0x%x)", cmd);
+ return -EINVAL;
+ }
+
+ ret = panthor_pwr_domain_wait_transition(ptdev, domain, timeout_us);
+ if (ret)
+ return ret;
+
+ /* domain already in target state, return early */
+ if ((gpu_read64(ptdev, ready_reg) & mask) == expected_val)
+ return 0;
+
+ panthor_pwr_write_command(ptdev, pwr_cmd, mask);
+
+ ret = gpu_read64_poll_timeout(ptdev, ready_reg, val, (mask & val) == expected_val, 100,
+ timeout_us);
+ if (ret) {
+ drm_err(&ptdev->base,
+ "timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)",
+ get_domain_name(domain), pwr_cmd, mask);
+ panthor_pwr_debug_info_show(ptdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+#define panthor_pwr_domain_power_off(__ptdev, __domain, __mask, __timeout_us) \
+ panthor_pwr_domain_transition(__ptdev, PWR_COMMAND_POWER_DOWN, __domain, __mask, \
+ __timeout_us)
+
+#define panthor_pwr_domain_power_on(__ptdev, __domain, __mask, __timeout_us) \
+ panthor_pwr_domain_transition(__ptdev, PWR_COMMAND_POWER_UP, __domain, __mask, __timeout_us)
+
+/**
+ * retract_domain() - Retract control of a domain from MCU
+ * @ptdev: Device.
+ * @domain: Domain to retract the control
+ *
+ * Retracting L2 domain is not expected since it won't be delegated.
+ *
+ * Return: 0 on success or retracted already.
+ * -EPERM if domain is L2.
+ * A negative error code otherwise.
+ */
+static int retract_domain(struct panthor_device *ptdev, u32 domain)
+{
+ const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0);
+ const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
+ const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
+ u64 val;
+ int ret;
+
+ if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
+ return -EPERM;
+
+ ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val),
+ 0, PWR_RETRACT_TIMEOUT_US);
+ if (ret) {
+ drm_err(&ptdev->base, "%s domain retract pending", get_domain_name(domain));
+ return ret;
+ }
+
+ if (!(pwr_status & delegated_mask)) {
+ drm_dbg(&ptdev->base, "%s domain already retracted", get_domain_name(domain));
+ return 0;
+ }
+
+ panthor_pwr_write_command(ptdev, pwr_cmd, 0);
+
+ /*
+ * On successful retraction
+ * allow-flag will be set with delegated-flag being cleared.
+ */
+ ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
+ ((delegated_mask | allow_mask) & val) == allow_mask, 10,
+ PWR_TRANSITION_TIMEOUT_US);
+ if (ret) {
+ drm_err(&ptdev->base, "Retracting %s domain timeout, cmd(0x%x)",
+ get_domain_name(domain), pwr_cmd);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * delegate_domain() - Delegate control of a domain to MCU
+ * @ptdev: Device.
+ * @domain: Domain to delegate the control
+ *
+ * Delegating L2 domain is prohibited.
+ *
+ * Return:
+ * * 0 on success or delegated already.
+ * * -EPERM if domain is L2.
+ * * A negative error code otherwise.
+ */
+static int delegate_domain(struct panthor_device *ptdev, u32 domain)
+{
+ const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0);
+ const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
+ const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
+ u64 val;
+ int ret;
+
+ if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
+ return -EPERM;
+
+ /* Already delegated, exit early */
+ if (pwr_status & delegated_mask)
+ return 0;
+
+ /* Check if the command is allowed before delegating. */
+ if (!(pwr_status & allow_mask)) {
+ drm_warn(&ptdev->base, "Delegating %s domain not allowed", get_domain_name(domain));
+ return -EPERM;
+ }
+
+ ret = panthor_pwr_domain_wait_transition(ptdev, domain, PWR_TRANSITION_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ panthor_pwr_write_command(ptdev, pwr_cmd, 0);
+
+ /*
+ * On successful delegation
+ * allow-flag will be cleared with delegated-flag being set.
+ */
+ ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
+ ((delegated_mask | allow_mask) & val) == delegated_mask,
+ 10, PWR_TRANSITION_TIMEOUT_US);
+ if (ret) {
+ drm_err(&ptdev->base, "Delegating %s domain timeout, cmd(0x%x)",
+ get_domain_name(domain), pwr_cmd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int panthor_pwr_delegate_domains(struct panthor_device *ptdev)
+{
+ int ret;
+
+ if (!ptdev->pwr)
+ return 0;
+
+ ret = delegate_domain(ptdev, PWR_COMMAND_DOMAIN_SHADER);
+ if (ret)
+ return ret;
+
+ ret = delegate_domain(ptdev, PWR_COMMAND_DOMAIN_TILER);
+ if (ret)
+ goto err_retract_shader;
+
+ return 0;
+
+err_retract_shader:
+ retract_domain(ptdev, PWR_COMMAND_DOMAIN_SHADER);
+
+ return ret;
+}
+
+/**
+ * panthor_pwr_domain_force_off - Forcefully power down a domain.
+ * @ptdev: Device.
+ * @domain: Domain to forcefully power down.
+ *
+ * This function will attempt to retract and power off the requested power
+ * domain. However, if retraction fails, the operation is aborted. If power off
+ * fails, the domain will remain retracted and under the host control.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain)
+{
+ const u64 domain_ready = gpu_read64(ptdev, get_domain_ready_reg(domain));
+ int ret;
+
+ /* Domain already powered down, early exit. */
+ if (!domain_ready)
+ return 0;
+
+ /* Domain has to be in host control to issue power off command. */
+ ret = retract_domain(ptdev, domain);
+ if (ret)
+ return ret;
+
+ return panthor_pwr_domain_power_off(ptdev, domain, domain_ready, PWR_TRANSITION_TIMEOUT_US);
+}
+
void panthor_pwr_unplug(struct panthor_device *ptdev)
{
unsigned long flags;
@@ -103,6 +428,59 @@ int panthor_pwr_init(struct panthor_device *ptdev)
return 0;
}
+void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
+{
+ const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
+ const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+
+ /* Abort if L2 power off constraints are not satisfied */
+ if (!(pwr_status & l2_allow_mask)) {
+ drm_warn(&ptdev->base, "Power off L2 domain not allowed");
+ return;
+ }
+
+ /* It is expected that when halting the MCU, it would power down its
+ * delegated domains. However, an unresponsive or hung MCU may not do
+ * so, which is why we need to check and retract the domains back into
+ * host control to be powered down in the right order before powering
+ * down the L2.
+ */
+ if (panthor_pwr_domain_force_off(ptdev, PWR_COMMAND_DOMAIN_TILER))
+ return;
+
+ if (panthor_pwr_domain_force_off(ptdev, PWR_COMMAND_DOMAIN_SHADER))
+ return;
+
+ panthor_pwr_domain_power_off(ptdev, PWR_COMMAND_DOMAIN_L2, ptdev->gpu_info.l2_present,
+ PWR_TRANSITION_TIMEOUT_US);
+}
+
+int panthor_pwr_l2_power_on(struct panthor_device *ptdev)
+{
+ const u32 pwr_status = gpu_read64(ptdev, PWR_STATUS);
+ const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
+ int ret;
+
+ if ((pwr_status & l2_allow_mask) == 0) {
+ drm_warn(&ptdev->base, "Power on L2 domain not allowed");
+ return -EPERM;
+ }
+
+ ret = panthor_pwr_domain_power_on(ptdev, PWR_COMMAND_DOMAIN_L2, ptdev->gpu_info.l2_present,
+ PWR_TRANSITION_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Delegate control of the shader and tiler power domains to the MCU as
+ * it can better manage which shader/tiler cores need to be powered up
+ * or can be powered down based on currently running jobs.
+ *
+ * If the shader and tiler domains are already delegated to the MCU,
+ * this call would just return early.
+ */
+ return panthor_pwr_delegate_domains(ptdev);
+}
+
void panthor_pwr_suspend(struct panthor_device *ptdev)
{
if (!ptdev->pwr)
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.h b/drivers/gpu/drm/panthor/panthor_pwr.h
index b325e5b7eba3..3c834059a860 100644
--- a/drivers/gpu/drm/panthor/panthor_pwr.h
+++ b/drivers/gpu/drm/panthor/panthor_pwr.h
@@ -10,6 +10,10 @@ void panthor_pwr_unplug(struct panthor_device *ptdev);
int panthor_pwr_init(struct panthor_device *ptdev);
+void panthor_pwr_l2_power_off(struct panthor_device *ptdev);
+
+int panthor_pwr_l2_power_on(struct panthor_device *ptdev);
+
void panthor_pwr_suspend(struct panthor_device *ptdev);
void panthor_pwr_resume(struct panthor_device *ptdev);
diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h
index 5469eec02178..18702d7001e2 100644
--- a/drivers/gpu/drm/panthor/panthor_regs.h
+++ b/drivers/gpu/drm/panthor/panthor_regs.h
@@ -72,6 +72,7 @@
#define GPU_FEATURES 0x60
#define GPU_FEATURES_RAY_INTERSECTION BIT(2)
+#define GPU_FEATURES_RAY_TRAVERSAL BIT(5)
#define GPU_TIMESTAMP_OFFSET 0x88
#define GPU_CYCLE_COUNT 0x90
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 5/8] drm/panthor: Implement soft reset via PWR_CONTROL
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (3 preceding siblings ...)
2025-10-27 16:13 ` [PATCH v3 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 10:26 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
` (3 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Add helpers to issue reset commands through the PWR_CONTROL interface
and wait for reset completion using IRQ signaling. This enables support
for RESET_SOFT operations with timeout handling and status verification.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v2:
* Dropped RESET_FAST implementation as it is not currently being used.
* Renamed reset_completed to reset_pending to align with underlying
logic and fixed the logic of its callers accordingly.
* Improved readability of panthor_pwr_reset() and removed inline
ternary expressions.
---
drivers/gpu/drm/panthor/panthor_pwr.c | 50 +++++++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_pwr.h | 2 ++
2 files changed, 52 insertions(+)
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
index cd529660a276..4edb818c7ac4 100644
--- a/drivers/gpu/drm/panthor/panthor_pwr.c
+++ b/drivers/gpu/drm/panthor/panthor_pwr.c
@@ -3,6 +3,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/cleanup.h>
#include <linux/iopoll.h>
#include <linux/wait.h>
@@ -31,6 +32,8 @@
#define PWR_RETRACT_TIMEOUT_US (2ULL * USEC_PER_MSEC)
+#define PWR_RESET_TIMEOUT_MS 500
+
/**
* struct panthor_pwr - PWR_CONTROL block management data.
*/
@@ -75,6 +78,43 @@ static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command,
gpu_write(ptdev, PWR_COMMAND, command);
}
+static bool reset_irq_raised(struct panthor_device *ptdev)
+{
+ return gpu_read(ptdev, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED;
+}
+
+static bool reset_pending(struct panthor_device *ptdev)
+{
+ return (ptdev->pwr->pending_reqs & PWR_IRQ_RESET_COMPLETED);
+}
+
+static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)
+{
+ scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) {
+ if (reset_pending(ptdev)) {
+ drm_WARN(&ptdev->base, 1, "Reset already pending");
+ } else {
+ ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED;
+ gpu_write(ptdev, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED);
+ panthor_pwr_write_command(ptdev, reset_cmd, 0);
+ }
+ }
+
+ if (!wait_event_timeout(ptdev->pwr->reqs_acked, !reset_pending(ptdev),
+ msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {
+ guard(spinlock_irqsave)(&ptdev->pwr->reqs_lock);
+
+ if (reset_pending(ptdev) && !reset_irq_raised(ptdev)) {
+ drm_err(&ptdev->base, "RESET timed out (0x%x)", reset_cmd);
+ return -ETIMEDOUT;
+ }
+
+ ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED;
+ }
+
+ return 0;
+}
+
static const char *get_domain_name(u8 domain)
{
switch (domain) {
@@ -428,6 +468,16 @@ int panthor_pwr_init(struct panthor_device *ptdev)
return 0;
}
+int panthor_pwr_reset_soft(struct panthor_device *ptdev)
+{
+ if (!(gpu_read64(ptdev, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) {
+ drm_err(&ptdev->base, "RESET_SOFT not allowed");
+ return -EOPNOTSUPP;
+ }
+
+ return panthor_pwr_reset(ptdev, PWR_COMMAND_RESET_SOFT);
+}
+
void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
{
const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.h b/drivers/gpu/drm/panthor/panthor_pwr.h
index 3c834059a860..adf1f6136abc 100644
--- a/drivers/gpu/drm/panthor/panthor_pwr.h
+++ b/drivers/gpu/drm/panthor/panthor_pwr.h
@@ -10,6 +10,8 @@ void panthor_pwr_unplug(struct panthor_device *ptdev);
int panthor_pwr_init(struct panthor_device *ptdev);
+int panthor_pwr_reset_soft(struct panthor_device *ptdev);
+
void panthor_pwr_l2_power_off(struct panthor_device *ptdev);
int panthor_pwr_l2_power_on(struct panthor_device *ptdev);
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (4 preceding siblings ...)
2025-10-27 16:13 ` [PATCH v3 5/8] drm/panthor: Implement soft reset " Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 10:50 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1 Karunika Choo
` (2 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Add support for the GLB_REQ.STATE field introduced in CSF v4.1+, which
replaces the HALT bit to provide finer control over the MCU state. This
change implements basic handling for transitioning the MCU between
ACTIVE and HALT states on Mali-G1 GPUs.
The update introduces new helpers to issue the state change requests,
poll for MCU halt completion, and restore the MCU to an active state
after halting.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v3:
* Fixed missed CSF_IFACE_VERSION check with pathor_fw_has_glb_state().
v2:
* Reduced MCU_HALT_TIMEOUT_US to 1 second.
* Wrap the CSG_IFACE_VERSION checks for v4.1.0 with
panthor_fw_has_glb_state().
* Removed use of undefined panthor_fw_csf_version() MACRO.
---
drivers/gpu/drm/panthor/panthor_fw.c | 89 +++++++++++++++++++++++-----
drivers/gpu/drm/panthor/panthor_fw.h | 7 +++
2 files changed, 80 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index e6c39c70d348..fb1f69ef76fb 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -33,6 +33,7 @@
#define PROGRESS_TIMEOUT_SCALE_SHIFT 10
#define IDLE_HYSTERESIS_US 800
#define PWROFF_HYSTERESIS_US 10000
+#define MCU_HALT_TIMEOUT_US (1ULL * USEC_PER_SEC)
/**
* struct panthor_fw_binary_hdr - Firmware binary header.
@@ -317,6 +318,13 @@ panthor_fw_get_cs_iface(struct panthor_device *ptdev, u32 csg_slot, u32 cs_slot)
return &ptdev->fw->iface.streams[csg_slot][cs_slot];
}
+static bool panthor_fw_has_glb_state(struct panthor_device *ptdev)
+{
+ struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
+
+ return glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0);
+}
+
/**
* panthor_fw_conv_timeout() - Convert a timeout into a cycle-count
* @ptdev: Device.
@@ -996,6 +1004,9 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
GLB_IDLE_EN |
GLB_IDLE;
+ if (panthor_fw_has_glb_state(ptdev))
+ glb_iface->input->ack_irq_mask |= GLB_STATE_MASK;
+
panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN, GLB_IDLE_EN);
panthor_fw_toggle_reqs(glb_iface, req, ack,
GLB_CFG_ALLOC_EN |
@@ -1069,6 +1080,54 @@ static void panthor_fw_stop(struct panthor_device *ptdev)
drm_err(&ptdev->base, "Failed to stop MCU");
}
+static bool panthor_fw_mcu_halted(struct panthor_device *ptdev)
+{
+ struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
+ bool halted;
+
+ halted = gpu_read(ptdev, MCU_STATUS) == MCU_STATUS_HALT;
+
+ if (panthor_fw_has_glb_state(ptdev))
+ halted &= (GLB_STATE_GET(glb_iface->output->ack) == GLB_STATE_HALT);
+
+ return halted;
+}
+
+static void panthor_fw_halt_mcu(struct panthor_device *ptdev)
+{
+ struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
+
+ if (panthor_fw_has_glb_state(ptdev))
+ panthor_fw_update_reqs(glb_iface, req, GLB_STATE(GLB_STATE_HALT), GLB_STATE_MASK);
+ else
+ panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT);
+
+ gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
+}
+
+static bool panthor_fw_wait_mcu_halted(struct panthor_device *ptdev)
+{
+ bool halted = false;
+
+ if (read_poll_timeout_atomic(panthor_fw_mcu_halted, halted, halted, 10,
+ MCU_HALT_TIMEOUT_US, 0, ptdev)) {
+ drm_warn(&ptdev->base, "Timed out waiting for MCU to halt");
+ return false;
+ }
+
+ return true;
+}
+
+static void panthor_fw_mcu_set_active(struct panthor_device *ptdev)
+{
+ struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
+
+ if (panthor_fw_has_glb_state(ptdev))
+ panthor_fw_update_reqs(glb_iface, req, GLB_STATE(GLB_STATE_ACTIVE), GLB_STATE_MASK);
+ else
+ panthor_fw_update_reqs(glb_iface, req, 0, GLB_HALT);
+}
+
/**
* panthor_fw_pre_reset() - Call before a reset.
* @ptdev: Device.
@@ -1085,19 +1144,13 @@ void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang)
ptdev->reset.fast = false;
if (!on_hang) {
- struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
- u32 status;
-
- 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->reset.fast = true;
- } else {
+ panthor_fw_halt_mcu(ptdev);
+ if (!panthor_fw_wait_mcu_halted(ptdev))
drm_warn(&ptdev->base, "Failed to cleanly suspend MCU");
- }
+ else
+ ptdev->reset.fast = true;
}
+ panthor_fw_stop(ptdev);
panthor_job_irq_suspend(&ptdev->fw->irq);
}
@@ -1125,14 +1178,14 @@ int panthor_fw_post_reset(struct panthor_device *ptdev)
*/
panthor_reload_fw_sections(ptdev, true);
} else {
- /* The FW detects 0 -> 1 transitions. Make sure we reset
- * the HALT bit before the FW is rebooted.
+ /*
+ * If the FW was previously successfully halted in the pre-reset
+ * operation, we need to transition it to active again before
+ * the FW is rebooted.
* This is not needed on a slow reset because FW sections are
* re-initialized.
*/
- struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
-
- panthor_fw_update_reqs(glb_iface, req, 0, GLB_HALT);
+ panthor_fw_mcu_set_active(ptdev);
}
ret = panthor_fw_start(ptdev);
@@ -1170,6 +1223,10 @@ void panthor_fw_unplug(struct panthor_device *ptdev)
if (ptdev->fw->irq.irq)
panthor_job_irq_suspend(&ptdev->fw->irq);
+ panthor_fw_halt_mcu(ptdev);
+ if (!panthor_fw_wait_mcu_halted(ptdev))
+ drm_warn(&ptdev->base, "Failed to halt MCU on unplug");
+
panthor_fw_stop(ptdev);
}
diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h
index 6598d96c6d2a..a19ed48b2d0b 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.h
+++ b/drivers/gpu/drm/panthor/panthor_fw.h
@@ -214,6 +214,13 @@ struct panthor_fw_global_input_iface {
#define GLB_FWCFG_UPDATE BIT(9)
#define GLB_IDLE_EN BIT(10)
#define GLB_SLEEP BIT(12)
+#define GLB_STATE_MASK GENMASK(14, 12)
+#define GLB_STATE_ACTIVE 0
+#define GLB_STATE_HALT 1
+#define GLB_STATE_SLEEP 2
+#define GLB_STATE_SUSPEND 3
+#define GLB_STATE(x) (((x) << 12) & GLB_STATE_MASK)
+#define GLB_STATE_GET(x) (((x) & GLB_STATE_MASK) >> 12)
#define GLB_INACTIVE_COMPUTE BIT(20)
#define GLB_INACTIVE_FRAGMENT BIT(21)
#define GLB_INACTIVE_TILER BIT(22)
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (5 preceding siblings ...)
2025-10-27 16:13 ` [PATCH v3 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 10:59 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 8/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-11-07 11:05 ` [PATCH v3 0/8] " Boris Brezillon
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Add support for the 64-bit endpoint_req register introduced in CSF v4.0+
GPUs. Unlike a simple register widening, the 64-bit variant occupies the
next 64 bits after the original 32-bit field, requiring
version-dependent access.
This change introduces helper functions to read, write, and update the
endpoint_req register, ensuring correct handling on both pre-v4.0 and
v4.0+ firmwares.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v2:
* Wrap the CSG_IFACE_VERSION checks for v4.0.0 with
panthor_fw_has_64bit_ep_req().
* Removed wrongly included code from previous patch.
* Reordered CSG_EP_REQ_PRIORITY_GET() and CSG_EP_REQ_PRIORITY() to
reuse CSG_EP_REQ_PRIORITY_MASK definition.
* Updated panthor_fw_csg_endpoint_req_*() functions to accept CSG iface
structure instead of a CSG id.
* Update endpoint_req variables to u64.
* Minor readability and code quality fixes.
---
drivers/gpu/drm/panthor/panthor_fw.c | 36 +++++++++++++++++++++++++
drivers/gpu/drm/panthor/panthor_fw.h | 25 +++++++++++++++--
drivers/gpu/drm/panthor/panthor_sched.c | 21 +++++++++------
3 files changed, 72 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index fb1f69ef76fb..2ab974c9a09d 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -325,6 +325,42 @@ static bool panthor_fw_has_glb_state(struct panthor_device *ptdev)
return glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0);
}
+static bool panthor_fw_has_64bit_ep_req(struct panthor_device *ptdev)
+{
+ struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
+
+ return glb_iface->control->version >= CSF_IFACE_VERSION(4, 0, 0);
+}
+
+u64 panthor_fw_csg_endpoint_req_get(struct panthor_device *ptdev,
+ struct panthor_fw_csg_iface *csg_iface)
+{
+ if (panthor_fw_has_64bit_ep_req(ptdev))
+ return csg_iface->input->endpoint_req2;
+ else
+ return csg_iface->input->endpoint_req;
+}
+
+void panthor_fw_csg_endpoint_req_set(struct panthor_device *ptdev,
+ struct panthor_fw_csg_iface *csg_iface, u64 value)
+{
+ if (panthor_fw_has_64bit_ep_req(ptdev))
+ csg_iface->input->endpoint_req2 = value;
+ else
+ csg_iface->input->endpoint_req = lower_32_bits(value);
+}
+
+void panthor_fw_csg_endpoint_req_update(struct panthor_device *ptdev,
+ struct panthor_fw_csg_iface *csg_iface, u64 value,
+ u64 mask)
+{
+ if (panthor_fw_has_64bit_ep_req(ptdev))
+ panthor_fw_update_reqs64(csg_iface, endpoint_req2, value, mask);
+ else
+ panthor_fw_update_reqs(csg_iface, endpoint_req, lower_32_bits(value),
+ lower_32_bits(mask));
+}
+
/**
* panthor_fw_conv_timeout() - Convert a timeout into a cycle-count
* @ptdev: Device.
diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h
index a19ed48b2d0b..fbdc21469ba3 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.h
+++ b/drivers/gpu/drm/panthor/panthor_fw.h
@@ -167,10 +167,11 @@ struct panthor_fw_csg_input_iface {
#define CSG_EP_REQ_TILER(x) (((x) << 16) & GENMASK(19, 16))
#define CSG_EP_REQ_EXCL_COMPUTE BIT(20)
#define CSG_EP_REQ_EXCL_FRAGMENT BIT(21)
-#define CSG_EP_REQ_PRIORITY(x) (((x) << 28) & GENMASK(31, 28))
#define CSG_EP_REQ_PRIORITY_MASK GENMASK(31, 28)
+#define CSG_EP_REQ_PRIORITY(x) (((x) << 28) & CSG_EP_REQ_PRIORITY_MASK)
+#define CSG_EP_REQ_PRIORITY_GET(x) (((x) & CSG_EP_REQ_PRIORITY_MASK) >> 28)
u32 endpoint_req;
- u32 reserved2[2];
+ u64 endpoint_req2;
u64 suspend_buf;
u64 protm_suspend_buf;
u32 config;
@@ -464,6 +465,16 @@ struct panthor_fw_global_iface {
spin_unlock(&(__iface)->lock); \
} while (0)
+#define panthor_fw_update_reqs64(__iface, __in_reg, __val, __mask) \
+ do { \
+ u64 __cur_val, __new_val; \
+ spin_lock(&(__iface)->lock); \
+ __cur_val = READ_ONCE((__iface)->input->__in_reg); \
+ __new_val = (__cur_val & ~(__mask)) | ((__val) & (__mask)); \
+ WRITE_ONCE((__iface)->input->__in_reg, __new_val); \
+ spin_unlock(&(__iface)->lock); \
+ } while (0)
+
struct panthor_fw_global_iface *
panthor_fw_get_glb_iface(struct panthor_device *ptdev);
@@ -473,6 +484,16 @@ panthor_fw_get_csg_iface(struct panthor_device *ptdev, u32 csg_slot);
struct panthor_fw_cs_iface *
panthor_fw_get_cs_iface(struct panthor_device *ptdev, u32 csg_slot, u32 cs_slot);
+u64 panthor_fw_csg_endpoint_req_get(struct panthor_device *ptdev,
+ struct panthor_fw_csg_iface *csg_iface);
+
+void panthor_fw_csg_endpoint_req_set(struct panthor_device *ptdev,
+ struct panthor_fw_csg_iface *csg_iface, u64 value);
+
+void panthor_fw_csg_endpoint_req_update(struct panthor_device *ptdev,
+ struct panthor_fw_csg_iface *csg_iface, u64 value,
+ u64 mask);
+
int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_id, u32 req_mask,
u32 *acked, u32 timeout_ms);
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 0cc9055f4ee5..d6f5efc10312 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -1139,11 +1139,13 @@ csg_slot_sync_priority_locked(struct panthor_device *ptdev, u32 csg_id)
{
struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id];
struct panthor_fw_csg_iface *csg_iface;
+ u64 endpoint_req;
lockdep_assert_held(&ptdev->scheduler->lock);
csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id);
- csg_slot->priority = (csg_iface->input->endpoint_req & CSG_EP_REQ_PRIORITY_MASK) >> 28;
+ endpoint_req = panthor_fw_csg_endpoint_req_get(ptdev, csg_iface);
+ csg_slot->priority = CSG_EP_REQ_PRIORITY_GET(endpoint_req);
}
/**
@@ -1303,6 +1305,7 @@ csg_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 priority)
struct panthor_csg_slot *csg_slot;
struct panthor_group *group;
u32 queue_mask = 0, i;
+ u64 endpoint_req;
lockdep_assert_held(&ptdev->scheduler->lock);
@@ -1329,10 +1332,12 @@ csg_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 priority)
csg_iface->input->allow_compute = group->compute_core_mask;
csg_iface->input->allow_fragment = group->fragment_core_mask;
csg_iface->input->allow_other = group->tiler_core_mask;
- csg_iface->input->endpoint_req = CSG_EP_REQ_COMPUTE(group->max_compute_cores) |
- CSG_EP_REQ_FRAGMENT(group->max_fragment_cores) |
- CSG_EP_REQ_TILER(group->max_tiler_cores) |
- CSG_EP_REQ_PRIORITY(priority);
+ endpoint_req = CSG_EP_REQ_COMPUTE(group->max_compute_cores) |
+ CSG_EP_REQ_FRAGMENT(group->max_fragment_cores) |
+ CSG_EP_REQ_TILER(group->max_tiler_cores) |
+ CSG_EP_REQ_PRIORITY(priority);
+ panthor_fw_csg_endpoint_req_set(ptdev, csg_iface, endpoint_req);
+
csg_iface->input->config = panthor_vm_as(group->vm);
if (group->suspend_buf)
@@ -2230,9 +2235,9 @@ tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_ctx *c
continue;
}
- panthor_fw_update_reqs(csg_iface, endpoint_req,
- CSG_EP_REQ_PRIORITY(new_csg_prio),
- CSG_EP_REQ_PRIORITY_MASK);
+ panthor_fw_csg_endpoint_req_update(ptdev, csg_iface,
+ CSG_EP_REQ_PRIORITY(new_csg_prio),
+ CSG_EP_REQ_PRIORITY_MASK);
csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id,
csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG,
CSG_ENDPOINT_CONFIG);
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 8/8] drm/panthor: Add support for Mali-G1 GPUs
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (6 preceding siblings ...)
2025-10-27 16:13 ` [PATCH v3 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1 Karunika Choo
@ 2025-10-27 16:13 ` Karunika Choo
2025-11-07 11:00 ` Steven Price
2025-11-07 11:05 ` [PATCH v3 0/8] " Boris Brezillon
8 siblings, 1 reply; 19+ messages in thread
From: Karunika Choo @ 2025-10-27 16:13 UTC (permalink / raw)
To: dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Add support for Mali-G1 GPUs (CSF architecture v14), introducing a new
panthor_hw_arch_v14 entry with reset and L2 power management operations
via the PWR_CONTROL block.
Mali-G1 introduces a dedicated PWR_CONTROL block for managing resets and
power domains. panthor_gpu_info_init() is updated to use this block for
L2, tiler, and shader domain present register reads.
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
---
v3:
* Fixed some includes.
v2:
* Removed feature bits usage.
* Check panthor_hw_has_pwr_ctrl() to read the correct *_PRESENT
registers instead of reading reserved registers on newer GPUs.
---
drivers/gpu/drm/panthor/panthor_fw.c | 1 +
drivers/gpu/drm/panthor/panthor_hw.c | 35 ++++++++++++++++++++++++----
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 2ab974c9a09d..9450a917e66b 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -1501,3 +1501,4 @@ MODULE_FIRMWARE("arm/mali/arch10.12/mali_csffw.bin");
MODULE_FIRMWARE("arm/mali/arch11.8/mali_csffw.bin");
MODULE_FIRMWARE("arm/mali/arch12.8/mali_csffw.bin");
MODULE_FIRMWARE("arm/mali/arch13.8/mali_csffw.bin");
+MODULE_FIRMWARE("arm/mali/arch14.8/mali_csffw.bin");
diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
index 1041201d83e5..263d4a525686 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -4,6 +4,7 @@
#include "panthor_device.h"
#include "panthor_gpu.h"
#include "panthor_hw.h"
+#include "panthor_pwr.h"
#define GPU_PROD_ID_MAKE(arch_major, prod_major) \
(((arch_major) << 24) | (prod_major))
@@ -28,12 +29,25 @@ static struct panthor_hw panthor_hw_arch_v10 = {
},
};
+static struct panthor_hw panthor_hw_arch_v14 = {
+ .ops = {
+ .soft_reset = panthor_pwr_reset_soft,
+ .l2_power_off = panthor_pwr_l2_power_off,
+ .l2_power_on = panthor_pwr_l2_power_on,
+ },
+};
+
static struct panthor_hw_entry panthor_hw_match[] = {
{
.arch_min = 10,
.arch_max = 13,
.hwdev = &panthor_hw_arch_v10,
},
+ {
+ .arch_min = 14,
+ .arch_max = 14,
+ .hwdev = &panthor_hw_arch_v14,
+ },
};
static char *get_gpu_model_name(struct panthor_device *ptdev)
@@ -81,6 +95,12 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
fallthrough;
case GPU_PROD_ID_MAKE(13, 1):
return "Mali-G625";
+ case GPU_PROD_ID_MAKE(14, 0):
+ return "Mali-G1-Ultra";
+ case GPU_PROD_ID_MAKE(14, 1):
+ return "Mali-G1-Premium";
+ case GPU_PROD_ID_MAKE(14, 3):
+ return "Mali-G1-Pro";
}
return "(Unknown Mali GPU)";
@@ -107,12 +127,19 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT);
- ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT);
- ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
- ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
-
/* Introduced in arch 11.x */
ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES);
+
+ if (panthor_hw_has_pwr_ctrl(ptdev)) {
+ /* Introduced in arch 14.x */
+ ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT);
+ ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT);
+ ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT);
+ } else {
+ ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT);
+ ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
+ ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
+ }
}
static void panthor_hw_info_init(struct panthor_device *ptdev)
--
2.49.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding
2025-10-27 16:13 ` [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
@ 2025-10-28 16:16 ` Liviu Dudau
2025-11-07 9:24 ` Steven Price
0 siblings, 1 reply; 19+ messages in thread
From: Liviu Dudau @ 2025-10-28 16:16 UTC (permalink / raw)
To: Karunika Choo
Cc: dri-devel, nd, Boris Brezillon, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
Hello,
On Mon, Oct 27, 2025 at 04:13:27PM +0000, Karunika Choo wrote:
> This patch adds the framework for binding to a specific panthor_hw
> structure based on the architecture major value parsed from the GPU_ID
> register. This is in preparation of enabling architecture-specific
> behaviours based on GPU_ID. As such, it also splits the GPU_ID register
> read operation into its own helper function.
>
> This framework allows a single panthor_hw structure to be shared across
> multiple architectures should there be minimal changes between them via
> the arch_min and arch_max field of the panthor_hw_entry structure,
> instead of duplicating the structure across multiple architectures.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
> ---
> v2:
> * merged GPU_ID refactoring patch with the arch-specific panthor_hw
> binding patch (PATCH 01/10 and PATCH 02/10 in v1).
> ---
> drivers/gpu/drm/panthor/panthor_device.h | 4 ++
> drivers/gpu/drm/panthor/panthor_hw.c | 65 +++++++++++++++++++++++-
> drivers/gpu/drm/panthor/panthor_hw.h | 6 +++
> 3 files changed, 74 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
> index a764111359d2..1457c1255f1f 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.h
> +++ b/drivers/gpu/drm/panthor/panthor_device.h
> @@ -26,6 +26,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_fw;
> @@ -122,6 +123,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;
>
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 4f2858114e5e..b6e7401327c3 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -8,6 +8,28 @@
> #define GPU_PROD_ID_MAKE(arch_major, prod_major) \
> (((arch_major) << 24) | (prod_major))
>
> +/** struct panthor_hw_entry - HW arch major to panthor_hw binding entry */
> +struct panthor_hw_entry {
> + /** @arch_min: Minimum supported architecture major value (inclusive) */
> + u8 arch_min;
> +
> + /** @arch_max: Maximum supported architecture major value (inclusive) */
> + u8 arch_max;
I'm not a big fan of this [min, max] range definition. I would expect that,
unless a new panthor_hw_entry is defined, the one covering arch X will also
cover arch X+1 automatically. With the current implementation we will have
to add a patch extending arch_max for an existing panthor_hw_entry when a new
GPU architecture is released that is compatible with the previous one at the
panthor_hw level *and backport the patch* for older kernels if they can
support that hardware.
My suggestion is to drop this structure entirely and change panthor_hw_bind_device()
to a cascade of if()s starting with the latest arch to have a struct panthor_hw
defined. For this patch the function will actually just set ptdev->hw to panthor_hw_arch_v10
without any ifs.
Also (this is my personal preference) I would merge patch 1/8 and 2/8 so that we
don't have just empty structures defined.
Best regards,
Liviu
> +
> + /** @hwdev: Pointer to panthor_hw structure */
> + struct panthor_hw *hwdev;
> +};
> +
> +static struct panthor_hw panthor_hw_arch_v10 = {};
> +
> +static struct panthor_hw_entry panthor_hw_match[] = {
> + {
> + .arch_min = 10,
> + .arch_max = 13,
> + .hwdev = &panthor_hw_arch_v10,
> + },
> +};
> +
> static char *get_gpu_model_name(struct panthor_device *ptdev)
> {
> const u32 gpu_id = ptdev->gpu_info.gpu_id;
> @@ -62,7 +84,6 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
> {
> unsigned int i;
>
> - ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
> ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID);
> ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID);
> ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES);
> @@ -117,8 +138,50 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
> ptdev->gpu_info.tiler_present);
> }
>
> +static int panthor_hw_bind_device(struct panthor_device *ptdev)
> +{
> + struct panthor_hw *hdev = NULL;
> + const u32 arch_major = GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id);
> + int i = 0;
> +
> + for (i = 0; i < ARRAY_SIZE(panthor_hw_match); i++) {
> + struct panthor_hw_entry *entry = &panthor_hw_match[i];
> +
> + if (arch_major >= entry->arch_min && arch_major <= entry->arch_max) {
> + hdev = entry->hwdev;
> + break;
> + }
> + }
> +
> + if (!hdev)
> + return -EOPNOTSUPP;
> +
> + ptdev->hw = hdev;
> +
> + return 0;
> +}
> +
> +static int panthor_hw_gpu_id_init(struct panthor_device *ptdev)
> +{
> + ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
> + if (!ptdev->gpu_info.gpu_id)
> + return -ENXIO;
> +
> + return 0;
> +}
> +
> int panthor_hw_init(struct panthor_device *ptdev)
> {
> + int ret = 0;
> +
> + ret = panthor_hw_gpu_id_init(ptdev);
> + if (ret)
> + return ret;
> +
> + ret = panthor_hw_bind_device(ptdev);
> + if (ret)
> + return ret;
> +
> panthor_hw_info_init(ptdev);
>
> return 0;
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
> index 0af6acc6aa6a..39752de3e7ad 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.h
> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
> @@ -6,6 +6,12 @@
>
> struct panthor_device;
>
> +/**
> + * struct panthor_hw - GPU specific register mapping and functions
> + */
> +struct panthor_hw {
> +};
> +
> int panthor_hw_init(struct panthor_device *ptdev);
>
> #endif /* __PANTHOR_HW_H__ */
> --
> 2.49.0
>
--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding
2025-10-28 16:16 ` Liviu Dudau
@ 2025-11-07 9:24 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 9:24 UTC (permalink / raw)
To: Liviu Dudau, Karunika Choo
Cc: dri-devel, nd, Boris Brezillon, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, linux-kernel
On 28/10/2025 16:16, Liviu Dudau wrote:
> Hello,
>
> On Mon, Oct 27, 2025 at 04:13:27PM +0000, Karunika Choo wrote:
>> This patch adds the framework for binding to a specific panthor_hw
>> structure based on the architecture major value parsed from the GPU_ID
>> register. This is in preparation of enabling architecture-specific
>> behaviours based on GPU_ID. As such, it also splits the GPU_ID register
>> read operation into its own helper function.
>>
>> This framework allows a single panthor_hw structure to be shared across
>> multiple architectures should there be minimal changes between them via
>> the arch_min and arch_max field of the panthor_hw_entry structure,
>> instead of duplicating the structure across multiple architectures.
>>
>> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
>> ---
>> v2:
>> * merged GPU_ID refactoring patch with the arch-specific panthor_hw
>> binding patch (PATCH 01/10 and PATCH 02/10 in v1).
>> ---
>> drivers/gpu/drm/panthor/panthor_device.h | 4 ++
>> drivers/gpu/drm/panthor/panthor_hw.c | 65 +++++++++++++++++++++++-
>> drivers/gpu/drm/panthor/panthor_hw.h | 6 +++
>> 3 files changed, 74 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
>> index a764111359d2..1457c1255f1f 100644
>> --- a/drivers/gpu/drm/panthor/panthor_device.h
>> +++ b/drivers/gpu/drm/panthor/panthor_device.h
>> @@ -26,6 +26,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_fw;
>> @@ -122,6 +123,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;
>>
>> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
>> index 4f2858114e5e..b6e7401327c3 100644
>> --- a/drivers/gpu/drm/panthor/panthor_hw.c
>> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
>> @@ -8,6 +8,28 @@
>> #define GPU_PROD_ID_MAKE(arch_major, prod_major) \
>> (((arch_major) << 24) | (prod_major))
>>
>> +/** struct panthor_hw_entry - HW arch major to panthor_hw binding entry */
>> +struct panthor_hw_entry {
>> + /** @arch_min: Minimum supported architecture major value (inclusive) */
>> + u8 arch_min;
>> +
>> + /** @arch_max: Maximum supported architecture major value (inclusive) */
>> + u8 arch_max;
>
> I'm not a big fan of this [min, max] range definition. I would expect that,
> unless a new panthor_hw_entry is defined, the one covering arch X will also
> cover arch X+1 automatically. With the current implementation we will have
> to add a patch extending arch_max for an existing panthor_hw_entry when a new
> GPU architecture is released that is compatible with the previous one at the
> panthor_hw level *and backport the patch* for older kernels if they can
> support that hardware.
I see your point, but I'm not sure it's necessarily a good idea for
kernels to pretend to support architectures that haven't been released
yet. Historically we haven't been great at keeping compatibility with
newer hardware and we might otherwise end up backporting patches just to
explicitly break compatibility if we didn't have a max.
Of course you have a much better idea of what's in the pipeline and
whether future GPUs are going to be better at backwards compatiblity...
> My suggestion is to drop this structure entirely and change panthor_hw_bind_device()
> to a cascade of if()s starting with the latest arch to have a struct panthor_hw
> defined. For this patch the function will actually just set ptdev->hw to panthor_hw_arch_v10
> without any ifs.
I'm not a fan of cascades of if()s. If we can express it as a simple
table it will be much easier to read and maintain.
> Also (this is my personal preference) I would merge patch 1/8 and 2/8 so that we
> don't have just empty structures defined.
I'd usually agree, but there's a rename in the following patch which I
think should be kept separate from these changes. So I think you'd still
need a rename patch (panthor_gpu_soft_reset => panthor_hw_soft_reset
etc) separate.
Thanks,
Steve
> Best regards,
> Liviu
>
>> +
>> + /** @hwdev: Pointer to panthor_hw structure */
>> + struct panthor_hw *hwdev;
>> +};
>> +
>> +static struct panthor_hw panthor_hw_arch_v10 = {};
>> +
>> +static struct panthor_hw_entry panthor_hw_match[] = {
>> + {
>> + .arch_min = 10,
>> + .arch_max = 13,
>> + .hwdev = &panthor_hw_arch_v10,
>> + },
>> +};
>> +
>> static char *get_gpu_model_name(struct panthor_device *ptdev)
>> {
>> const u32 gpu_id = ptdev->gpu_info.gpu_id;
>> @@ -62,7 +84,6 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
>> {
>> unsigned int i;
>>
>> - ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
>> ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID);
>> ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID);
>> ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES);
>> @@ -117,8 +138,50 @@ static void panthor_hw_info_init(struct panthor_device *ptdev)
>> ptdev->gpu_info.tiler_present);
>> }
>>
>> +static int panthor_hw_bind_device(struct panthor_device *ptdev)
>> +{
>> + struct panthor_hw *hdev = NULL;
>> + const u32 arch_major = GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id);
>> + int i = 0;
>> +
>> + for (i = 0; i < ARRAY_SIZE(panthor_hw_match); i++) {
>> + struct panthor_hw_entry *entry = &panthor_hw_match[i];
>> +
>> + if (arch_major >= entry->arch_min && arch_major <= entry->arch_max) {
>> + hdev = entry->hwdev;
>> + break;
>> + }
>> + }
>> +
>> + if (!hdev)
>> + return -EOPNOTSUPP;
>> +
>> + ptdev->hw = hdev;
>> +
>> + return 0;
>> +}
>> +
>> +static int panthor_hw_gpu_id_init(struct panthor_device *ptdev)
>> +{
>> + ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
>> + if (!ptdev->gpu_info.gpu_id)
>> + return -ENXIO;
>> +
>> + return 0;
>> +}
>> +
>> int panthor_hw_init(struct panthor_device *ptdev)
>> {
>> + int ret = 0;
>> +
>> + ret = panthor_hw_gpu_id_init(ptdev);
>> + if (ret)
>> + return ret;
>> +
>> + ret = panthor_hw_bind_device(ptdev);
>> + if (ret)
>> + return ret;
>> +
>> panthor_hw_info_init(ptdev);
>>
>> return 0;
>> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
>> index 0af6acc6aa6a..39752de3e7ad 100644
>> --- a/drivers/gpu/drm/panthor/panthor_hw.h
>> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
>> @@ -6,6 +6,12 @@
>>
>> struct panthor_device;
>>
>> +/**
>> + * struct panthor_hw - GPU specific register mapping and functions
>> + */
>> +struct panthor_hw {
>> +};
>> +
>> int panthor_hw_init(struct panthor_device *ptdev);
>>
>> #endif /* __PANTHOR_HW_H__ */
>> --
>> 2.49.0
>>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 2/8] drm/panthor: Add architecture-specific function operations
2025-10-27 16:13 ` [PATCH v3 2/8] drm/panthor: Add architecture-specific function operations Karunika Choo
@ 2025-11-07 9:48 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 9:48 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> Introduce architecture-specific function pointers to support
> architecture-dependent behaviours. This patch adds the following
> function pointers and updates their usage accordingly:
>
> - soft_reset
> - l2_power_on
> - l2_power_off
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
> ---
> v3:
> * Reverted includes changes to align with the include behaviour of the
> rest of the driver while enabling the definition of static inline
> function pointer accessors.
> * Moved the function pointer accessors from panthor_device.h to
> panthor_hw.h
> v2:
> * Updated includes for panthor_hw.h to allow static inline function
> pointer accessor functions instead of MACROs.
> * updated l2_power_off function signature to void instead of returning
> int as we have no way of handling a failure in this case.
> ---
> drivers/gpu/drm/panthor/panthor_device.c | 4 +--
> drivers/gpu/drm/panthor/panthor_device.h | 1 -
> drivers/gpu/drm/panthor/panthor_fw.c | 5 ++--
> drivers/gpu/drm/panthor/panthor_gpu.c | 12 ++++++--
> drivers/gpu/drm/panthor/panthor_gpu.h | 1 +
> drivers/gpu/drm/panthor/panthor_hw.c | 9 +++++-
> drivers/gpu/drm/panthor/panthor_hw.h | 35 +++++++++++++++++++++++-
> 7 files changed, 57 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
> index 81df49880bd8..847dea458682 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.c
> +++ b/drivers/gpu/drm/panthor/panthor_device.c
> @@ -141,8 +141,8 @@ static void panthor_device_reset_work(struct work_struct *work)
> 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);
> + panthor_hw_soft_reset(ptdev);
> + panthor_hw_l2_power_on(ptdev);
> panthor_mmu_post_reset(ptdev);
> ret = panthor_fw_post_reset(ptdev);
> atomic_set(&ptdev->reset.pending, 0);
> diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
> index 1457c1255f1f..f8e37a24d081 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.h
> +++ b/drivers/gpu/drm/panthor/panthor_device.h
> @@ -26,7 +26,6 @@ struct panthor_device;
> struct panthor_gpu;
> struct panthor_group_pool;
> struct panthor_heap_pool;
> -struct panthor_hw;
I don't understand this change. Was it left over from the include changes?
With that fixed:
Reviewed-by: Steven Price <steven.price@arm.com>
> struct panthor_job;
> struct panthor_mmu;
> struct panthor_fw;
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
> index 9bf06e55eaee..e6c39c70d348 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_regs.h"
> #include "panthor_sched.h"
> @@ -1184,7 +1185,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);
> + panthor_hw_l2_power_off(ptdev);
> }
>
> /**
> @@ -1363,7 +1364,7 @@ int panthor_fw_init(struct panthor_device *ptdev)
> return ret;
> }
>
> - ret = panthor_gpu_l2_power_on(ptdev);
> + ret = panthor_hw_l2_power_on(ptdev);
> if (ret)
> return ret;
>
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index db69449a5be0..63ed8c461796 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -18,6 +18,7 @@
>
> #include "panthor_device.h"
> #include "panthor_gpu.h"
> +#include "panthor_hw.h"
> #include "panthor_regs.h"
>
> /**
> @@ -218,6 +219,11 @@ int panthor_gpu_block_power_on(struct panthor_device *ptdev,
> return 0;
> }
>
> +void panthor_gpu_l2_power_off(struct panthor_device *ptdev)
> +{
> + panthor_gpu_power_off(ptdev, L2, ptdev->gpu_info.l2_present, 20000);
> +}
> +
> /**
> * panthor_gpu_l2_power_on() - Power-on the L2-cache
> * @ptdev: Device.
> @@ -344,9 +350,9 @@ void panthor_gpu_suspend(struct panthor_device *ptdev)
> {
> /* On a fast reset, simply power down the L2. */
> if (!ptdev->reset.fast)
> - panthor_gpu_soft_reset(ptdev);
> + panthor_hw_soft_reset(ptdev);
> else
> - panthor_gpu_power_off(ptdev, L2, 1, 20000);
> + panthor_hw_l2_power_off(ptdev);
>
> panthor_gpu_irq_suspend(&ptdev->gpu->irq);
> }
> @@ -361,6 +367,6 @@ 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);
> + panthor_hw_l2_power_on(ptdev);
> }
>
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/panthor/panthor_gpu.h
> index 7c17a8c06858..12e66f48ced1 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, \
> mask, timeout_us)
>
> +void 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
> index b6e7401327c3..ed0ebd53f4ba 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -2,6 +2,7 @@
> /* Copyright 2025 ARM Limited. All rights reserved. */
>
> #include "panthor_device.h"
> +#include "panthor_gpu.h"
> #include "panthor_hw.h"
> #include "panthor_regs.h"
>
> @@ -20,7 +21,13 @@ struct panthor_hw_entry {
> struct panthor_hw *hwdev;
> };
>
> -static struct panthor_hw panthor_hw_arch_v10 = {};
> +static struct panthor_hw panthor_hw_arch_v10 = {
> + .ops = {
> + .soft_reset = panthor_gpu_soft_reset,
> + .l2_power_off = panthor_gpu_l2_power_off,
> + .l2_power_on = panthor_gpu_l2_power_on,
> + },
> +};
>
> static struct panthor_hw_entry panthor_hw_match[] = {
> {
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
> index 39752de3e7ad..64616caa6f05 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.h
> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
> @@ -4,14 +4,47 @@
> #ifndef __PANTHOR_HW_H__
> #define __PANTHOR_HW_H__
>
> -struct panthor_device;
> +#include "panthor_device.h"
> +
> +/**
> + * 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 */
> + void (*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 {
> + /** @features: Bitmap containing panthor_hw_feature */
> +
> + /** @ops: Panthor HW specific operations */
> + struct panthor_hw_ops ops;
> };
>
> int panthor_hw_init(struct panthor_device *ptdev);
>
> +static inline int panthor_hw_soft_reset(struct panthor_device *ptdev)
> +{
> + return ptdev->hw->ops.soft_reset(ptdev);
> +}
> +
> +static inline int panthor_hw_l2_power_on(struct panthor_device *ptdev)
> +{
> + return ptdev->hw->ops.l2_power_on(ptdev);
> +}
> +
> +static inline void panthor_hw_l2_power_off(struct panthor_device *ptdev)
> +{
> + ptdev->hw->ops.l2_power_off(ptdev);
> +}
> +
> #endif /* __PANTHOR_HW_H__ */
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-27 16:13 ` [PATCH v3 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
@ 2025-11-07 10:07 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 10:07 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> Add the new panthor_pwr module, which provides basic power control
> management for Mali-G1 GPUs. The initial implementation includes
> infrastructure for initializing the PWR_CONTROL block, requesting and
> handling its IRQ, and checking for PWR_CONTROL support based on GPU
> architecture.
>
> The patch also integrates panthor_pwr with the device lifecycle (init,
> suspend, resume, and unplug) through the new API functions. It also
> registers the IRQ handler under the 'gpu' IRQ as the PWR_CONTROL block
> is located within the GPU_CONTROL block.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Generally fine, but two issues below.
> ---
> v3:
> * Turned panthor_hw_has_pwr_ctrl() into a static inline function.
> v2:
> * Removed stub functions.
> * Updated BIT() definitions for 64-bit fields to use BIT_U64() to
> address kernel test robot warnings for 32-bit systems.
> * Moved GPU_FEATURES_RAY_TRAVERSAL definition to the next patch where
> it is being used.
> * Drop the use of feature bits in favour of a function that performs a
> GPU_ARCH_MAJOR check instead.
> ---
> drivers/gpu/drm/panthor/Makefile | 1 +
> drivers/gpu/drm/panthor/panthor_device.c | 14 ++-
> drivers/gpu/drm/panthor/panthor_device.h | 4 +
> drivers/gpu/drm/panthor/panthor_hw.c | 1 -
> drivers/gpu/drm/panthor/panthor_hw.h | 6 ++
> drivers/gpu/drm/panthor/panthor_pwr.c | 120 +++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_pwr.h | 17 ++++
> drivers/gpu/drm/panthor/panthor_regs.h | 78 +++++++++++++++
> 8 files changed, 239 insertions(+), 2 deletions(-)
> create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.c
> create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.h
>
> diff --git a/drivers/gpu/drm/panthor/Makefile b/drivers/gpu/drm/panthor/Makefile
> index 02db21748c12..753a32c446df 100644
> --- a/drivers/gpu/drm/panthor/Makefile
> +++ b/drivers/gpu/drm/panthor/Makefile
> @@ -10,6 +10,7 @@ panthor-y := \
> panthor_heap.o \
> panthor_hw.o \
> panthor_mmu.o \
> + panthor_pwr.o \
> panthor_sched.o
>
> obj-$(CONFIG_DRM_PANTHOR) += panthor.o
> diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
> index 847dea458682..d3e16da0b24e 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.c
> +++ b/drivers/gpu/drm/panthor/panthor_device.c
> @@ -20,6 +20,7 @@
> #include "panthor_gpu.h"
> #include "panthor_hw.h"
> #include "panthor_mmu.h"
> +#include "panthor_pwr.h"
> #include "panthor_regs.h"
> #include "panthor_sched.h"
>
> @@ -102,6 +103,7 @@ void panthor_device_unplug(struct panthor_device *ptdev)
> panthor_fw_unplug(ptdev);
> panthor_mmu_unplug(ptdev);
> panthor_gpu_unplug(ptdev);
> + panthor_pwr_unplug(ptdev);
>
> pm_runtime_dont_use_autosuspend(ptdev->base.dev);
> pm_runtime_put_sync_suspend(ptdev->base.dev);
> @@ -249,10 +251,14 @@ int panthor_device_init(struct panthor_device *ptdev)
> if (ret)
> goto err_rpm_put;
>
> - ret = panthor_gpu_init(ptdev);
> + ret = panthor_pwr_init(ptdev);
> if (ret)
> goto err_rpm_put;
>
> + ret = panthor_gpu_init(ptdev);
> + if (ret)
> + goto err_unplug_pwr;
> +
> ret = panthor_gpu_coherency_init(ptdev);
> if (ret)
> goto err_unplug_gpu;
> @@ -293,6 +299,9 @@ int panthor_device_init(struct panthor_device *ptdev)
> err_unplug_gpu:
> panthor_gpu_unplug(ptdev);
>
> +err_unplug_pwr:
> + panthor_pwr_unplug(ptdev);
> +
> err_rpm_put:
> pm_runtime_put_sync_suspend(ptdev->base.dev);
> return ret;
> @@ -446,6 +455,7 @@ static int panthor_device_resume_hw_components(struct panthor_device *ptdev)
> {
> int ret;
>
> + panthor_pwr_resume(ptdev);
> panthor_gpu_resume(ptdev);
> panthor_mmu_resume(ptdev);
>
> @@ -455,6 +465,7 @@ static int panthor_device_resume_hw_components(struct panthor_device *ptdev)
>
> panthor_mmu_suspend(ptdev);
> panthor_gpu_suspend(ptdev);
> + panthor_pwr_suspend(ptdev);
> return ret;
> }
>
> @@ -568,6 +579,7 @@ int panthor_device_suspend(struct device *dev)
> panthor_fw_suspend(ptdev);
> panthor_mmu_suspend(ptdev);
> panthor_gpu_suspend(ptdev);
> + panthor_pwr_suspend(ptdev);
> drm_dev_exit(cookie);
> }
>
> diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
> index f8e37a24d081..5afa9fdfbc31 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.h
> +++ b/drivers/gpu/drm/panthor/panthor_device.h
> @@ -30,6 +30,7 @@ struct panthor_job;
> struct panthor_mmu;
> struct panthor_fw;
> struct panthor_perfcnt;
> +struct panthor_pwr;
> struct panthor_vm;
> struct panthor_vm_pool;
>
> @@ -125,6 +126,9 @@ struct panthor_device {
> /** @hw: GPU-specific data. */
> struct panthor_hw *hw;
>
> + /** @pwr: Power control management data. */
> + struct panthor_pwr *pwr;
> +
> /** @gpu: GPU management data. */
> struct panthor_gpu *gpu;
>
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index ed0ebd53f4ba..1041201d83e5 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -4,7 +4,6 @@
> #include "panthor_device.h"
> #include "panthor_gpu.h"
> #include "panthor_hw.h"
> -#include "panthor_regs.h"
I'm not a fan of relying on indirect includes. If we're using something
from panthor_regs.h then we should be including it.
>
> #define GPU_PROD_ID_MAKE(arch_major, prod_major) \
> (((arch_major) << 24) | (prod_major))
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
> index 64616caa6f05..56c68c1e9c26 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.h
> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
> @@ -5,6 +5,7 @@
> #define __PANTHOR_HW_H__
>
> #include "panthor_device.h"
> +#include "panthor_regs.h"
>
> /**
> * struct panthor_hw_ops - HW operations that are specific to a GPU
> @@ -47,4 +48,9 @@ static inline void panthor_hw_l2_power_off(struct panthor_device *ptdev)
> ptdev->hw->ops.l2_power_off(ptdev);
> }
>
> +static inline bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
> +{
> + return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
> +}
> +
> #endif /* __PANTHOR_HW_H__ */
> diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
> new file mode 100644
> index 000000000000..da64fe006a8b
> --- /dev/null
> +++ b/drivers/gpu/drm/panthor/panthor_pwr.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0 or MIT
> +/* Copyright 2025 ARM Limited. All rights reserved. */
> +
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/iopoll.h>
> +#include <linux/wait.h>
> +
> +#include <drm/drm_managed.h>
> +
> +#include "panthor_device.h"
> +#include "panthor_hw.h"
> +#include "panthor_pwr.h"
> +#include "panthor_regs.h"
> +
> +#define PWR_INTERRUPTS_MASK \
> + (PWR_IRQ_POWER_CHANGED_SINGLE | \
> + PWR_IRQ_POWER_CHANGED_ALL | \
> + PWR_IRQ_DELEGATION_CHANGED | \
> + PWR_IRQ_RESET_COMPLETED | \
> + PWR_IRQ_RETRACT_COMPLETED | \
> + PWR_IRQ_INSPECT_COMPLETED | \
> + PWR_IRQ_COMMAND_NOT_ALLOWED | \
> + PWR_IRQ_COMMAND_INVALID)
> +
> +/**
> + * struct panthor_pwr - PWR_CONTROL block management data.
> + */
> +struct panthor_pwr {
> + /** @irq: PWR irq. */
> + struct panthor_irq irq;
> +
> + /** @reqs_lock: Lock protecting access to pending_reqs. */
> + spinlock_t reqs_lock;
> +
> + /** @pending_reqs: Pending PWR requests. */
> + u32 pending_reqs;
> +
> + /** @reqs_acked: PWR request wait queue. */
> + wait_queue_head_t reqs_acked;
> +};
> +
> +static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
> +{
> + spin_lock(&ptdev->pwr->reqs_lock);
> + gpu_write(ptdev, PWR_INT_CLEAR, status);
> +
> + if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED))
> + drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED");
My test build shows you're missing an include of drm_print.h
Thanks,
Steve
> +
> + if (unlikely(status & PWR_IRQ_COMMAND_INVALID))
> + drm_err(&ptdev->base, "PWR_IRQ: COMMAND_INVALID");
> +
> + if (status & ptdev->pwr->pending_reqs) {
> + ptdev->pwr->pending_reqs &= ~status;
> + wake_up_all(&ptdev->pwr->reqs_acked);
> + }
> + spin_unlock(&ptdev->pwr->reqs_lock);
> +}
> +PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler);
> +
> +void panthor_pwr_unplug(struct panthor_device *ptdev)
> +{
> + unsigned long flags;
> +
> + if (!ptdev->pwr)
> + return;
> +
> + /* Make sure the IRQ handler is not running after that point. */
> + panthor_pwr_irq_suspend(&ptdev->pwr->irq);
> +
> + /* Wake-up all waiters. */
> + spin_lock_irqsave(&ptdev->pwr->reqs_lock, flags);
> + ptdev->pwr->pending_reqs = 0;
> + wake_up_all(&ptdev->pwr->reqs_acked);
> + spin_unlock_irqrestore(&ptdev->pwr->reqs_lock, flags);
> +}
> +
> +int panthor_pwr_init(struct panthor_device *ptdev)
> +{
> + struct panthor_pwr *pwr;
> + int err, irq;
> +
> + if (!panthor_hw_has_pwr_ctrl(ptdev))
> + return 0;
> +
> + pwr = drmm_kzalloc(&ptdev->base, sizeof(*pwr), GFP_KERNEL);
> + if (!pwr)
> + return -ENOMEM;
> +
> + spin_lock_init(&pwr->reqs_lock);
> + init_waitqueue_head(&pwr->reqs_acked);
> + ptdev->pwr = pwr;
> +
> + irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "gpu");
> + if (irq < 0)
> + return irq;
> +
> + err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK);
> + if (err)
> + return err;
> +
> + return 0;
> +}
> +
> +void panthor_pwr_suspend(struct panthor_device *ptdev)
> +{
> + if (!ptdev->pwr)
> + return;
> +
> + panthor_pwr_irq_suspend(&ptdev->pwr->irq);
> +}
> +
> +void panthor_pwr_resume(struct panthor_device *ptdev)
> +{
> + if (!ptdev->pwr)
> + return;
> +
> + panthor_pwr_irq_resume(&ptdev->pwr->irq, PWR_INTERRUPTS_MASK);
> +}
> diff --git a/drivers/gpu/drm/panthor/panthor_pwr.h b/drivers/gpu/drm/panthor/panthor_pwr.h
> new file mode 100644
> index 000000000000..b325e5b7eba3
> --- /dev/null
> +++ b/drivers/gpu/drm/panthor/panthor_pwr.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 or MIT */
> +/* Copyright 2025 ARM Limited. All rights reserved. */
> +
> +#ifndef __PANTHOR_PWR_H__
> +#define __PANTHOR_PWR_H__
> +
> +struct panthor_device;
> +
> +void panthor_pwr_unplug(struct panthor_device *ptdev);
> +
> +int panthor_pwr_init(struct panthor_device *ptdev);
> +
> +void panthor_pwr_suspend(struct panthor_device *ptdev);
> +
> +void panthor_pwr_resume(struct panthor_device *ptdev);
> +
> +#endif /* __PANTHOR_PWR_H__ */
> diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h
> index 8bee76d01bf8..5469eec02178 100644
> --- a/drivers/gpu/drm/panthor/panthor_regs.h
> +++ b/drivers/gpu/drm/panthor/panthor_regs.h
> @@ -205,4 +205,82 @@
> #define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000))
> #define CSF_GLB_DOORBELL_ID 0
>
> +/* PWR Control registers */
> +
> +#define PWR_CONTROL_BASE 0x800
> +#define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x))
> +
> +#define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0)
> +#define PWR_INT_CLEAR PWR_CTRL_REG(0x4)
> +#define PWR_INT_MASK PWR_CTRL_REG(0x8)
> +#define PWR_INT_STAT PWR_CTRL_REG(0xc)
> +#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0)
> +#define PWR_IRQ_POWER_CHANGED_ALL BIT(1)
> +#define PWR_IRQ_DELEGATION_CHANGED BIT(2)
> +#define PWR_IRQ_RESET_COMPLETED BIT(3)
> +#define PWR_IRQ_RETRACT_COMPLETED BIT(4)
> +#define PWR_IRQ_INSPECT_COMPLETED BIT(5)
> +#define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30)
> +#define PWR_IRQ_COMMAND_INVALID BIT(31)
> +
> +#define PWR_STATUS PWR_CTRL_REG(0x20)
> +#define PWR_STATUS_ALLOW_L2 BIT_U64(0)
> +#define PWR_STATUS_ALLOW_TILER BIT_U64(1)
> +#define PWR_STATUS_ALLOW_SHADER BIT_U64(8)
> +#define PWR_STATUS_ALLOW_BASE BIT_U64(14)
> +#define PWR_STATUS_ALLOW_STACK BIT_U64(15)
> +#define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x)
> +#define PWR_STATUS_DELEGATED_L2 BIT_U64(16)
> +#define PWR_STATUS_DELEGATED_TILER BIT_U64(17)
> +#define PWR_STATUS_DELEGATED_SHADER BIT_U64(24)
> +#define PWR_STATUS_DELEGATED_BASE BIT_U64(30)
> +#define PWR_STATUS_DELEGATED_STACK BIT_U64(31)
> +#define PWR_STATUS_DELEGATED_SHIFT 16
> +#define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT)
> +#define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33)
> +#define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34)
> +#define PWR_STATUS_POWER_PENDING BIT_U64(41)
> +#define PWR_STATUS_RESET_PENDING BIT_U64(42)
> +#define PWR_STATUS_RETRACT_PENDING BIT_U64(43)
> +#define PWR_STATUS_INSPECT_PENDING BIT_U64(44)
> +
> +#define PWR_COMMAND PWR_CTRL_REG(0x28)
> +#define PWR_COMMAND_POWER_UP 0x10
> +#define PWR_COMMAND_POWER_DOWN 0x11
> +#define PWR_COMMAND_DELEGATE 0x20
> +#define PWR_COMMAND_RETRACT 0x21
> +#define PWR_COMMAND_RESET_SOFT 0x31
> +#define PWR_COMMAND_RESET_FAST 0x32
> +#define PWR_COMMAND_INSPECT 0xF0
> +#define PWR_COMMAND_DOMAIN_L2 0
> +#define PWR_COMMAND_DOMAIN_TILER 1
> +#define PWR_COMMAND_DOMAIN_SHADER 8
> +#define PWR_COMMAND_DOMAIN_BASE 14
> +#define PWR_COMMAND_DOMAIN_STACK 15
> +#define PWR_COMMAND_SUBDOMAIN_RTU BIT(0)
> +#define PWR_COMMAND_DEF(cmd, domain, subdomain) \
> + (((subdomain) << 16) | ((domain) << 8) | (cmd))
> +
> +#define PWR_CMDARG PWR_CTRL_REG(0x30)
> +
> +#define PWR_L2_PRESENT PWR_CTRL_REG(0x100)
> +#define PWR_L2_READY PWR_CTRL_REG(0x108)
> +#define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110)
> +#define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118)
> +#define PWR_TILER_PRESENT PWR_CTRL_REG(0x140)
> +#define PWR_TILER_READY PWR_CTRL_REG(0x148)
> +#define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150)
> +#define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158)
> +#define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200)
> +#define PWR_SHADER_READY PWR_CTRL_REG(0x208)
> +#define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210)
> +#define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218)
> +#define PWR_BASE_PRESENT PWR_CTRL_REG(0x380)
> +#define PWR_BASE_READY PWR_CTRL_REG(0x388)
> +#define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390)
> +#define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398)
> +#define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0)
> +#define PWR_STACK_READY PWR_CTRL_REG(0x3c8)
> +#define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0)
> +
> #endif
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL
2025-10-27 16:13 ` [PATCH v3 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
@ 2025-11-07 10:18 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 10:18 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> This patch adds common helpers to issue power commands, poll
> transitions, and validate domain state, then wires them into the L2
> on/off paths.
>
> The L2 power-on sequence now delegates control of the SHADER and TILER
> domains to the MCU when allowed, while the L2 itself is never delegated.
> On power-off, dependent domains beneath the L2 are checked, and if
> necessary, retracted and powered down to maintain proper domain
> ordering.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
One NIT below, but otherwise,
Reviewed-by: Steven Price <steven.price@arm.com>
> ---
> v2:
> * Updated GENMASK to GENMASK_U64 to address kernel test robot warnings
> for 32-bit systems.
> * Removed panthor_pwr_read_status() in favour of a simple gpu_read64()
> operation on the PWR_STATUS register.
> * Renamed panthor_pwr_info_show() to panthor_pwr_debug_info_show() for
> more clarity.
> * Added additional WARN_ON for an invalid domain when requesting power
> domain transition.
> * Made panthor_pwr_domain_transition()'s expected val logic more
> readable and clearer.
> * Wait on domain power transition instead of failing the operation.
> * Fixed inconsistent error return value vs kerneldoc.
> * Removed confusing drm_dbg in delegate_domain() in favor of a comment.
> * Add unwind to panthor_pwr_delegate_domains().
> * Moved child domain handling logic from panthor_pwr_l2_power_off()
> into panthor_pwr_domain_force_off().
> * Added additional clarification regarding delegation and retraction of
> power domains.
> * Minor formatting and readability changes and remove unnecessary
> checks.
> ---
> drivers/gpu/drm/panthor/panthor_pwr.c | 378 +++++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_pwr.h | 4 +
> drivers/gpu/drm/panthor/panthor_regs.h | 1 +
> 3 files changed, 383 insertions(+)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
> index da64fe006a8b..cd529660a276 100644
> --- a/drivers/gpu/drm/panthor/panthor_pwr.c
> +++ b/drivers/gpu/drm/panthor/panthor_pwr.c
> @@ -23,6 +23,14 @@
> PWR_IRQ_COMMAND_NOT_ALLOWED | \
> PWR_IRQ_COMMAND_INVALID)
>
> +#define PWR_ALL_CORES_MASK GENMASK_U64(63, 0)
> +
> +#define PWR_DOMAIN_MAX_BITS 16
> +
> +#define PWR_TRANSITION_TIMEOUT_US (2ULL * USEC_PER_SEC)
> +
> +#define PWR_RETRACT_TIMEOUT_US (2ULL * USEC_PER_MSEC)
> +
> /**
> * struct panthor_pwr - PWR_CONTROL block management data.
> */
> @@ -59,6 +67,323 @@ static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
> }
> PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler);
>
> +static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args)
> +{
> + if (args)
> + gpu_write64(ptdev, PWR_CMDARG, args);
> +
> + gpu_write(ptdev, PWR_COMMAND, command);
> +}
> +
> +static const char *get_domain_name(u8 domain)
> +{
> + switch (domain) {
> + case PWR_COMMAND_DOMAIN_L2:
> + return "L2";
> + case PWR_COMMAND_DOMAIN_TILER:
> + return "Tiler";
> + case PWR_COMMAND_DOMAIN_SHADER:
> + return "Shader";
> + case PWR_COMMAND_DOMAIN_BASE:
> + return "Base";
> + case PWR_COMMAND_DOMAIN_STACK:
> + return "Stack";
> + }
> + return "Unknown";
> +}
> +
> +static u32 get_domain_base(u8 domain)
> +{
> + switch (domain) {
> + case PWR_COMMAND_DOMAIN_L2:
> + return PWR_L2_PRESENT;
> + case PWR_COMMAND_DOMAIN_TILER:
> + return PWR_TILER_PRESENT;
> + case PWR_COMMAND_DOMAIN_SHADER:
> + return PWR_SHADER_PRESENT;
> + case PWR_COMMAND_DOMAIN_BASE:
> + return PWR_BASE_PRESENT;
> + case PWR_COMMAND_DOMAIN_STACK:
> + return PWR_STACK_PRESENT;
> + }
> + return 0;
> +}
> +
> +static u32 get_domain_ready_reg(u32 domain)
> +{
> + return get_domain_base(domain) + (PWR_L2_READY - PWR_L2_PRESENT);
> +}
> +
> +static u32 get_domain_pwrtrans_reg(u32 domain)
> +{
> + return get_domain_base(domain) + (PWR_L2_PWRTRANS - PWR_L2_PRESENT);
> +}
> +
> +static bool is_valid_domain(u32 domain)
> +{
> + return get_domain_base(domain) != 0;
> +}
> +
> +static bool has_rtu(struct panthor_device *ptdev)
> +{
> + return ptdev->gpu_info.gpu_features & GPU_FEATURES_RAY_TRAVERSAL;
> +}
> +
> +static u8 get_domain_subdomain(struct panthor_device *ptdev, u32 domain)
> +{
> + if ((domain == PWR_COMMAND_DOMAIN_SHADER) && has_rtu(ptdev))
NIT: Extra brackets
Thanks,
Steve
> + return PWR_COMMAND_SUBDOMAIN_RTU;
> +
> + return 0;
> +}
> +
> +static int panthor_pwr_domain_wait_transition(struct panthor_device *ptdev, u32 domain,
> + u32 timeout_us)
> +{
> + u32 pwrtrans_reg = get_domain_pwrtrans_reg(domain);
> + u64 val;
> + int ret = 0;
> +
> + ret = gpu_read64_poll_timeout(ptdev, pwrtrans_reg, val, !(PWR_ALL_CORES_MASK & val), 100,
> + timeout_us);
> + if (ret) {
> + drm_err(&ptdev->base, "%s domain power in transition, pwrtrans(0x%llx)",
> + get_domain_name(domain), val);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void panthor_pwr_debug_info_show(struct panthor_device *ptdev)
> +{
> + drm_info(&ptdev->base, "GPU_FEATURES: 0x%016llx", gpu_read64(ptdev, GPU_FEATURES));
> + drm_info(&ptdev->base, "PWR_STATUS: 0x%016llx", gpu_read64(ptdev, PWR_STATUS));
> + drm_info(&ptdev->base, "L2_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_L2_PRESENT));
> + drm_info(&ptdev->base, "L2_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_L2_PWRTRANS));
> + drm_info(&ptdev->base, "L2_READY: 0x%016llx", gpu_read64(ptdev, PWR_L2_READY));
> + drm_info(&ptdev->base, "TILER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PRESENT));
> + drm_info(&ptdev->base, "TILER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_TILER_PWRTRANS));
> + drm_info(&ptdev->base, "TILER_READY: 0x%016llx", gpu_read64(ptdev, PWR_TILER_READY));
> + drm_info(&ptdev->base, "SHADER_PRESENT: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PRESENT));
> + drm_info(&ptdev->base, "SHADER_PWRTRANS: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_PWRTRANS));
> + drm_info(&ptdev->base, "SHADER_READY: 0x%016llx", gpu_read64(ptdev, PWR_SHADER_READY));
> +}
> +
> +static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd, u32 domain,
> + u64 mask, u32 timeout_us)
> +{
> + u32 ready_reg = get_domain_ready_reg(domain);
> + u32 pwr_cmd = PWR_COMMAND_DEF(cmd, domain, get_domain_subdomain(ptdev, domain));
> + u64 expected_val = 0;
> + u64 val;
> + int ret = 0;
> +
> + if (drm_WARN_ON(&ptdev->base, !is_valid_domain(domain)))
> + return -EINVAL;
> +
> + switch (cmd) {
> + case PWR_COMMAND_POWER_DOWN:
> + expected_val = 0;
> + break;
> + case PWR_COMMAND_POWER_UP:
> + expected_val = mask;
> + break;
> + default:
> + drm_err(&ptdev->base, "Invalid power domain transition command (0x%x)", cmd);
> + return -EINVAL;
> + }
> +
> + ret = panthor_pwr_domain_wait_transition(ptdev, domain, timeout_us);
> + if (ret)
> + return ret;
> +
> + /* domain already in target state, return early */
> + if ((gpu_read64(ptdev, ready_reg) & mask) == expected_val)
> + return 0;
> +
> + panthor_pwr_write_command(ptdev, pwr_cmd, mask);
> +
> + ret = gpu_read64_poll_timeout(ptdev, ready_reg, val, (mask & val) == expected_val, 100,
> + timeout_us);
> + if (ret) {
> + drm_err(&ptdev->base,
> + "timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)",
> + get_domain_name(domain), pwr_cmd, mask);
> + panthor_pwr_debug_info_show(ptdev);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +#define panthor_pwr_domain_power_off(__ptdev, __domain, __mask, __timeout_us) \
> + panthor_pwr_domain_transition(__ptdev, PWR_COMMAND_POWER_DOWN, __domain, __mask, \
> + __timeout_us)
> +
> +#define panthor_pwr_domain_power_on(__ptdev, __domain, __mask, __timeout_us) \
> + panthor_pwr_domain_transition(__ptdev, PWR_COMMAND_POWER_UP, __domain, __mask, __timeout_us)
> +
> +/**
> + * retract_domain() - Retract control of a domain from MCU
> + * @ptdev: Device.
> + * @domain: Domain to retract the control
> + *
> + * Retracting L2 domain is not expected since it won't be delegated.
> + *
> + * Return: 0 on success or retracted already.
> + * -EPERM if domain is L2.
> + * A negative error code otherwise.
> + */
> +static int retract_domain(struct panthor_device *ptdev, u32 domain)
> +{
> + const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_RETRACT, domain, 0);
> + const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
> + const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
> + const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
> + u64 val;
> + int ret;
> +
> + if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
> + return -EPERM;
> +
> + ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val, !(PWR_STATUS_RETRACT_PENDING & val),
> + 0, PWR_RETRACT_TIMEOUT_US);
> + if (ret) {
> + drm_err(&ptdev->base, "%s domain retract pending", get_domain_name(domain));
> + return ret;
> + }
> +
> + if (!(pwr_status & delegated_mask)) {
> + drm_dbg(&ptdev->base, "%s domain already retracted", get_domain_name(domain));
> + return 0;
> + }
> +
> + panthor_pwr_write_command(ptdev, pwr_cmd, 0);
> +
> + /*
> + * On successful retraction
> + * allow-flag will be set with delegated-flag being cleared.
> + */
> + ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
> + ((delegated_mask | allow_mask) & val) == allow_mask, 10,
> + PWR_TRANSITION_TIMEOUT_US);
> + if (ret) {
> + drm_err(&ptdev->base, "Retracting %s domain timeout, cmd(0x%x)",
> + get_domain_name(domain), pwr_cmd);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * delegate_domain() - Delegate control of a domain to MCU
> + * @ptdev: Device.
> + * @domain: Domain to delegate the control
> + *
> + * Delegating L2 domain is prohibited.
> + *
> + * Return:
> + * * 0 on success or delegated already.
> + * * -EPERM if domain is L2.
> + * * A negative error code otherwise.
> + */
> +static int delegate_domain(struct panthor_device *ptdev, u32 domain)
> +{
> + const u32 pwr_cmd = PWR_COMMAND_DEF(PWR_COMMAND_DELEGATE, domain, 0);
> + const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
> + const u64 allow_mask = PWR_STATUS_DOMAIN_ALLOWED(domain);
> + const u64 delegated_mask = PWR_STATUS_DOMAIN_DELEGATED(domain);
> + u64 val;
> + int ret;
> +
> + if (drm_WARN_ON(&ptdev->base, domain == PWR_COMMAND_DOMAIN_L2))
> + return -EPERM;
> +
> + /* Already delegated, exit early */
> + if (pwr_status & delegated_mask)
> + return 0;
> +
> + /* Check if the command is allowed before delegating. */
> + if (!(pwr_status & allow_mask)) {
> + drm_warn(&ptdev->base, "Delegating %s domain not allowed", get_domain_name(domain));
> + return -EPERM;
> + }
> +
> + ret = panthor_pwr_domain_wait_transition(ptdev, domain, PWR_TRANSITION_TIMEOUT_US);
> + if (ret)
> + return ret;
> +
> + panthor_pwr_write_command(ptdev, pwr_cmd, 0);
> +
> + /*
> + * On successful delegation
> + * allow-flag will be cleared with delegated-flag being set.
> + */
> + ret = gpu_read64_poll_timeout(ptdev, PWR_STATUS, val,
> + ((delegated_mask | allow_mask) & val) == delegated_mask,
> + 10, PWR_TRANSITION_TIMEOUT_US);
> + if (ret) {
> + drm_err(&ptdev->base, "Delegating %s domain timeout, cmd(0x%x)",
> + get_domain_name(domain), pwr_cmd);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int panthor_pwr_delegate_domains(struct panthor_device *ptdev)
> +{
> + int ret;
> +
> + if (!ptdev->pwr)
> + return 0;
> +
> + ret = delegate_domain(ptdev, PWR_COMMAND_DOMAIN_SHADER);
> + if (ret)
> + return ret;
> +
> + ret = delegate_domain(ptdev, PWR_COMMAND_DOMAIN_TILER);
> + if (ret)
> + goto err_retract_shader;
> +
> + return 0;
> +
> +err_retract_shader:
> + retract_domain(ptdev, PWR_COMMAND_DOMAIN_SHADER);
> +
> + return ret;
> +}
> +
> +/**
> + * panthor_pwr_domain_force_off - Forcefully power down a domain.
> + * @ptdev: Device.
> + * @domain: Domain to forcefully power down.
> + *
> + * This function will attempt to retract and power off the requested power
> + * domain. However, if retraction fails, the operation is aborted. If power off
> + * fails, the domain will remain retracted and under the host control.
> + *
> + * Return: 0 on success or a negative error code on failure.
> + */
> +static int panthor_pwr_domain_force_off(struct panthor_device *ptdev, u32 domain)
> +{
> + const u64 domain_ready = gpu_read64(ptdev, get_domain_ready_reg(domain));
> + int ret;
> +
> + /* Domain already powered down, early exit. */
> + if (!domain_ready)
> + return 0;
> +
> + /* Domain has to be in host control to issue power off command. */
> + ret = retract_domain(ptdev, domain);
> + if (ret)
> + return ret;
> +
> + return panthor_pwr_domain_power_off(ptdev, domain, domain_ready, PWR_TRANSITION_TIMEOUT_US);
> +}
> +
> void panthor_pwr_unplug(struct panthor_device *ptdev)
> {
> unsigned long flags;
> @@ -103,6 +428,59 @@ int panthor_pwr_init(struct panthor_device *ptdev)
> return 0;
> }
>
> +void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
> +{
> + const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
> + const u64 pwr_status = gpu_read64(ptdev, PWR_STATUS);
> +
> + /* Abort if L2 power off constraints are not satisfied */
> + if (!(pwr_status & l2_allow_mask)) {
> + drm_warn(&ptdev->base, "Power off L2 domain not allowed");
> + return;
> + }
> +
> + /* It is expected that when halting the MCU, it would power down its
> + * delegated domains. However, an unresponsive or hung MCU may not do
> + * so, which is why we need to check and retract the domains back into
> + * host control to be powered down in the right order before powering
> + * down the L2.
> + */
> + if (panthor_pwr_domain_force_off(ptdev, PWR_COMMAND_DOMAIN_TILER))
> + return;
> +
> + if (panthor_pwr_domain_force_off(ptdev, PWR_COMMAND_DOMAIN_SHADER))
> + return;
> +
> + panthor_pwr_domain_power_off(ptdev, PWR_COMMAND_DOMAIN_L2, ptdev->gpu_info.l2_present,
> + PWR_TRANSITION_TIMEOUT_US);
> +}
> +
> +int panthor_pwr_l2_power_on(struct panthor_device *ptdev)
> +{
> + const u32 pwr_status = gpu_read64(ptdev, PWR_STATUS);
> + const u32 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
> + int ret;
> +
> + if ((pwr_status & l2_allow_mask) == 0) {
> + drm_warn(&ptdev->base, "Power on L2 domain not allowed");
> + return -EPERM;
> + }
> +
> + ret = panthor_pwr_domain_power_on(ptdev, PWR_COMMAND_DOMAIN_L2, ptdev->gpu_info.l2_present,
> + PWR_TRANSITION_TIMEOUT_US);
> + if (ret)
> + return ret;
> +
> + /* Delegate control of the shader and tiler power domains to the MCU as
> + * it can better manage which shader/tiler cores need to be powered up
> + * or can be powered down based on currently running jobs.
> + *
> + * If the shader and tiler domains are already delegated to the MCU,
> + * this call would just return early.
> + */
> + return panthor_pwr_delegate_domains(ptdev);
> +}
> +
> void panthor_pwr_suspend(struct panthor_device *ptdev)
> {
> if (!ptdev->pwr)
> diff --git a/drivers/gpu/drm/panthor/panthor_pwr.h b/drivers/gpu/drm/panthor/panthor_pwr.h
> index b325e5b7eba3..3c834059a860 100644
> --- a/drivers/gpu/drm/panthor/panthor_pwr.h
> +++ b/drivers/gpu/drm/panthor/panthor_pwr.h
> @@ -10,6 +10,10 @@ void panthor_pwr_unplug(struct panthor_device *ptdev);
>
> int panthor_pwr_init(struct panthor_device *ptdev);
>
> +void panthor_pwr_l2_power_off(struct panthor_device *ptdev);
> +
> +int panthor_pwr_l2_power_on(struct panthor_device *ptdev);
> +
> void panthor_pwr_suspend(struct panthor_device *ptdev);
>
> void panthor_pwr_resume(struct panthor_device *ptdev);
> diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h
> index 5469eec02178..18702d7001e2 100644
> --- a/drivers/gpu/drm/panthor/panthor_regs.h
> +++ b/drivers/gpu/drm/panthor/panthor_regs.h
> @@ -72,6 +72,7 @@
>
> #define GPU_FEATURES 0x60
> #define GPU_FEATURES_RAY_INTERSECTION BIT(2)
> +#define GPU_FEATURES_RAY_TRAVERSAL BIT(5)
>
> #define GPU_TIMESTAMP_OFFSET 0x88
> #define GPU_CYCLE_COUNT 0x90
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 5/8] drm/panthor: Implement soft reset via PWR_CONTROL
2025-10-27 16:13 ` [PATCH v3 5/8] drm/panthor: Implement soft reset " Karunika Choo
@ 2025-11-07 10:26 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 10:26 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> Add helpers to issue reset commands through the PWR_CONTROL interface
> and wait for reset completion using IRQ signaling. This enables support
> for RESET_SOFT operations with timeout handling and status verification.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
> ---
> v2:
> * Dropped RESET_FAST implementation as it is not currently being used.
> * Renamed reset_completed to reset_pending to align with underlying
> logic and fixed the logic of its callers accordingly.
> * Improved readability of panthor_pwr_reset() and removed inline
> ternary expressions.
> ---
> drivers/gpu/drm/panthor/panthor_pwr.c | 50 +++++++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_pwr.h | 2 ++
> 2 files changed, 52 insertions(+)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
> index cd529660a276..4edb818c7ac4 100644
> --- a/drivers/gpu/drm/panthor/panthor_pwr.c
> +++ b/drivers/gpu/drm/panthor/panthor_pwr.c
> @@ -3,6 +3,7 @@
>
> #include <linux/platform_device.h>
> #include <linux/interrupt.h>
> +#include <linux/cleanup.h>
> #include <linux/iopoll.h>
> #include <linux/wait.h>
>
> @@ -31,6 +32,8 @@
>
> #define PWR_RETRACT_TIMEOUT_US (2ULL * USEC_PER_MSEC)
>
> +#define PWR_RESET_TIMEOUT_MS 500
> +
> /**
> * struct panthor_pwr - PWR_CONTROL block management data.
> */
> @@ -75,6 +78,43 @@ static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command,
> gpu_write(ptdev, PWR_COMMAND, command);
> }
>
> +static bool reset_irq_raised(struct panthor_device *ptdev)
> +{
> + return gpu_read(ptdev, PWR_INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED;
> +}
> +
> +static bool reset_pending(struct panthor_device *ptdev)
> +{
> + return (ptdev->pwr->pending_reqs & PWR_IRQ_RESET_COMPLETED);
> +}
> +
> +static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)
> +{
> + scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) {
> + if (reset_pending(ptdev)) {
> + drm_WARN(&ptdev->base, 1, "Reset already pending");
> + } else {
> + ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED;
> + gpu_write(ptdev, PWR_INT_CLEAR, PWR_IRQ_RESET_COMPLETED);
> + panthor_pwr_write_command(ptdev, reset_cmd, 0);
> + }
> + }
> +
> + if (!wait_event_timeout(ptdev->pwr->reqs_acked, !reset_pending(ptdev),
> + msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {
> + guard(spinlock_irqsave)(&ptdev->pwr->reqs_lock);
> +
> + if (reset_pending(ptdev) && !reset_irq_raised(ptdev)) {
> + drm_err(&ptdev->base, "RESET timed out (0x%x)", reset_cmd);
> + return -ETIMEDOUT;
> + }
> +
> + ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED;
> + }
> +
> + return 0;
> +}
> +
> static const char *get_domain_name(u8 domain)
> {
> switch (domain) {
> @@ -428,6 +468,16 @@ int panthor_pwr_init(struct panthor_device *ptdev)
> return 0;
> }
>
> +int panthor_pwr_reset_soft(struct panthor_device *ptdev)
> +{
> + if (!(gpu_read64(ptdev, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) {
> + drm_err(&ptdev->base, "RESET_SOFT not allowed");
> + return -EOPNOTSUPP;
> + }
> +
> + return panthor_pwr_reset(ptdev, PWR_COMMAND_RESET_SOFT);
> +}
> +
> void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
> {
> const u64 l2_allow_mask = PWR_STATUS_DOMAIN_ALLOWED(PWR_COMMAND_DOMAIN_L2);
> diff --git a/drivers/gpu/drm/panthor/panthor_pwr.h b/drivers/gpu/drm/panthor/panthor_pwr.h
> index 3c834059a860..adf1f6136abc 100644
> --- a/drivers/gpu/drm/panthor/panthor_pwr.h
> +++ b/drivers/gpu/drm/panthor/panthor_pwr.h
> @@ -10,6 +10,8 @@ void panthor_pwr_unplug(struct panthor_device *ptdev);
>
> int panthor_pwr_init(struct panthor_device *ptdev);
>
> +int panthor_pwr_reset_soft(struct panthor_device *ptdev);
> +
> void panthor_pwr_l2_power_off(struct panthor_device *ptdev);
>
> int panthor_pwr_l2_power_on(struct panthor_device *ptdev);
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
2025-10-27 16:13 ` [PATCH v3 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
@ 2025-11-07 10:50 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 10:50 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> Add support for the GLB_REQ.STATE field introduced in CSF v4.1+, which
> replaces the HALT bit to provide finer control over the MCU state. This
> change implements basic handling for transitioning the MCU between
> ACTIVE and HALT states on Mali-G1 GPUs.
>
> The update introduces new helpers to issue the state change requests,
> poll for MCU halt completion, and restore the MCU to an active state
> after halting.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
> ---
> v3:
> * Fixed missed CSF_IFACE_VERSION check with pathor_fw_has_glb_state().
> v2:
> * Reduced MCU_HALT_TIMEOUT_US to 1 second.
> * Wrap the CSG_IFACE_VERSION checks for v4.1.0 with
> panthor_fw_has_glb_state().
> * Removed use of undefined panthor_fw_csf_version() MACRO.
> ---
> drivers/gpu/drm/panthor/panthor_fw.c | 89 +++++++++++++++++++++++-----
> drivers/gpu/drm/panthor/panthor_fw.h | 7 +++
> 2 files changed, 80 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
> index e6c39c70d348..fb1f69ef76fb 100644
> --- a/drivers/gpu/drm/panthor/panthor_fw.c
> +++ b/drivers/gpu/drm/panthor/panthor_fw.c
> @@ -33,6 +33,7 @@
> #define PROGRESS_TIMEOUT_SCALE_SHIFT 10
> #define IDLE_HYSTERESIS_US 800
> #define PWROFF_HYSTERESIS_US 10000
> +#define MCU_HALT_TIMEOUT_US (1ULL * USEC_PER_SEC)
>
> /**
> * struct panthor_fw_binary_hdr - Firmware binary header.
> @@ -317,6 +318,13 @@ panthor_fw_get_cs_iface(struct panthor_device *ptdev, u32 csg_slot, u32 cs_slot)
> return &ptdev->fw->iface.streams[csg_slot][cs_slot];
> }
>
> +static bool panthor_fw_has_glb_state(struct panthor_device *ptdev)
> +{
> + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> +
> + return glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0);
> +}
> +
> /**
> * panthor_fw_conv_timeout() - Convert a timeout into a cycle-count
> * @ptdev: Device.
> @@ -996,6 +1004,9 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
> GLB_IDLE_EN |
> GLB_IDLE;
>
> + if (panthor_fw_has_glb_state(ptdev))
> + glb_iface->input->ack_irq_mask |= GLB_STATE_MASK;
> +
> panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN, GLB_IDLE_EN);
> panthor_fw_toggle_reqs(glb_iface, req, ack,
> GLB_CFG_ALLOC_EN |
> @@ -1069,6 +1080,54 @@ static void panthor_fw_stop(struct panthor_device *ptdev)
> drm_err(&ptdev->base, "Failed to stop MCU");
> }
>
> +static bool panthor_fw_mcu_halted(struct panthor_device *ptdev)
> +{
> + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> + bool halted;
> +
> + halted = gpu_read(ptdev, MCU_STATUS) == MCU_STATUS_HALT;
> +
> + if (panthor_fw_has_glb_state(ptdev))
> + halted &= (GLB_STATE_GET(glb_iface->output->ack) == GLB_STATE_HALT);
> +
> + return halted;
> +}
> +
> +static void panthor_fw_halt_mcu(struct panthor_device *ptdev)
> +{
> + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> +
> + if (panthor_fw_has_glb_state(ptdev))
> + panthor_fw_update_reqs(glb_iface, req, GLB_STATE(GLB_STATE_HALT), GLB_STATE_MASK);
> + else
> + panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT);
> +
> + gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1);
> +}
> +
> +static bool panthor_fw_wait_mcu_halted(struct panthor_device *ptdev)
> +{
> + bool halted = false;
> +
> + if (read_poll_timeout_atomic(panthor_fw_mcu_halted, halted, halted, 10,
> + MCU_HALT_TIMEOUT_US, 0, ptdev)) {
> + drm_warn(&ptdev->base, "Timed out waiting for MCU to halt");
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static void panthor_fw_mcu_set_active(struct panthor_device *ptdev)
> +{
> + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> +
> + if (panthor_fw_has_glb_state(ptdev))
> + panthor_fw_update_reqs(glb_iface, req, GLB_STATE(GLB_STATE_ACTIVE), GLB_STATE_MASK);
> + else
> + panthor_fw_update_reqs(glb_iface, req, 0, GLB_HALT);
> +}
> +
> /**
> * panthor_fw_pre_reset() - Call before a reset.
> * @ptdev: Device.
> @@ -1085,19 +1144,13 @@ void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang)
> ptdev->reset.fast = false;
>
> if (!on_hang) {
> - struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> - u32 status;
> -
> - 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->reset.fast = true;
> - } else {
> + panthor_fw_halt_mcu(ptdev);
> + if (!panthor_fw_wait_mcu_halted(ptdev))
> drm_warn(&ptdev->base, "Failed to cleanly suspend MCU");
> - }
> + else
> + ptdev->reset.fast = true;
> }
> + panthor_fw_stop(ptdev);
>
> panthor_job_irq_suspend(&ptdev->fw->irq);
> }
> @@ -1125,14 +1178,14 @@ int panthor_fw_post_reset(struct panthor_device *ptdev)
> */
> panthor_reload_fw_sections(ptdev, true);
> } else {
> - /* The FW detects 0 -> 1 transitions. Make sure we reset
> - * the HALT bit before the FW is rebooted.
> + /*
> + * If the FW was previously successfully halted in the pre-reset
> + * operation, we need to transition it to active again before
> + * the FW is rebooted.
> * This is not needed on a slow reset because FW sections are
> * re-initialized.
> */
> - struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> -
> - panthor_fw_update_reqs(glb_iface, req, 0, GLB_HALT);
> + panthor_fw_mcu_set_active(ptdev);
> }
>
> ret = panthor_fw_start(ptdev);
> @@ -1170,6 +1223,10 @@ void panthor_fw_unplug(struct panthor_device *ptdev)
> if (ptdev->fw->irq.irq)
> panthor_job_irq_suspend(&ptdev->fw->irq);
>
> + panthor_fw_halt_mcu(ptdev);
> + if (!panthor_fw_wait_mcu_halted(ptdev))
> + drm_warn(&ptdev->base, "Failed to halt MCU on unplug");
> +
> panthor_fw_stop(ptdev);
> }
>
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h
> index 6598d96c6d2a..a19ed48b2d0b 100644
> --- a/drivers/gpu/drm/panthor/panthor_fw.h
> +++ b/drivers/gpu/drm/panthor/panthor_fw.h
> @@ -214,6 +214,13 @@ struct panthor_fw_global_input_iface {
> #define GLB_FWCFG_UPDATE BIT(9)
> #define GLB_IDLE_EN BIT(10)
> #define GLB_SLEEP BIT(12)
> +#define GLB_STATE_MASK GENMASK(14, 12)
> +#define GLB_STATE_ACTIVE 0
> +#define GLB_STATE_HALT 1
> +#define GLB_STATE_SLEEP 2
> +#define GLB_STATE_SUSPEND 3
> +#define GLB_STATE(x) (((x) << 12) & GLB_STATE_MASK)
> +#define GLB_STATE_GET(x) (((x) & GLB_STATE_MASK) >> 12)
> #define GLB_INACTIVE_COMPUTE BIT(20)
> #define GLB_INACTIVE_FRAGMENT BIT(21)
> #define GLB_INACTIVE_TILER BIT(22)
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1
2025-10-27 16:13 ` [PATCH v3 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1 Karunika Choo
@ 2025-11-07 10:59 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 10:59 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> Add support for the 64-bit endpoint_req register introduced in CSF v4.0+
> GPUs. Unlike a simple register widening, the 64-bit variant occupies the
> next 64 bits after the original 32-bit field, requiring
> version-dependent access.
>
> This change introduces helper functions to read, write, and update the
> endpoint_req register, ensuring correct handling on both pre-v4.0 and
> v4.0+ firmwares.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
> ---
> v2:
> * Wrap the CSG_IFACE_VERSION checks for v4.0.0 with
> panthor_fw_has_64bit_ep_req().
> * Removed wrongly included code from previous patch.
> * Reordered CSG_EP_REQ_PRIORITY_GET() and CSG_EP_REQ_PRIORITY() to
> reuse CSG_EP_REQ_PRIORITY_MASK definition.
> * Updated panthor_fw_csg_endpoint_req_*() functions to accept CSG iface
> structure instead of a CSG id.
> * Update endpoint_req variables to u64.
> * Minor readability and code quality fixes.
> ---
> drivers/gpu/drm/panthor/panthor_fw.c | 36 +++++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_fw.h | 25 +++++++++++++++--
> drivers/gpu/drm/panthor/panthor_sched.c | 21 +++++++++------
> 3 files changed, 72 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
> index fb1f69ef76fb..2ab974c9a09d 100644
> --- a/drivers/gpu/drm/panthor/panthor_fw.c
> +++ b/drivers/gpu/drm/panthor/panthor_fw.c
> @@ -325,6 +325,42 @@ static bool panthor_fw_has_glb_state(struct panthor_device *ptdev)
> return glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0);
> }
>
> +static bool panthor_fw_has_64bit_ep_req(struct panthor_device *ptdev)
> +{
> + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
> +
> + return glb_iface->control->version >= CSF_IFACE_VERSION(4, 0, 0);
> +}
> +
> +u64 panthor_fw_csg_endpoint_req_get(struct panthor_device *ptdev,
> + struct panthor_fw_csg_iface *csg_iface)
> +{
> + if (panthor_fw_has_64bit_ep_req(ptdev))
> + return csg_iface->input->endpoint_req2;
> + else
> + return csg_iface->input->endpoint_req;
> +}
> +
> +void panthor_fw_csg_endpoint_req_set(struct panthor_device *ptdev,
> + struct panthor_fw_csg_iface *csg_iface, u64 value)
> +{
> + if (panthor_fw_has_64bit_ep_req(ptdev))
> + csg_iface->input->endpoint_req2 = value;
> + else
> + csg_iface->input->endpoint_req = lower_32_bits(value);
> +}
> +
> +void panthor_fw_csg_endpoint_req_update(struct panthor_device *ptdev,
> + struct panthor_fw_csg_iface *csg_iface, u64 value,
> + u64 mask)
> +{
> + if (panthor_fw_has_64bit_ep_req(ptdev))
> + panthor_fw_update_reqs64(csg_iface, endpoint_req2, value, mask);
> + else
> + panthor_fw_update_reqs(csg_iface, endpoint_req, lower_32_bits(value),
> + lower_32_bits(mask));
> +}
> +
> /**
> * panthor_fw_conv_timeout() - Convert a timeout into a cycle-count
> * @ptdev: Device.
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor/panthor_fw.h
> index a19ed48b2d0b..fbdc21469ba3 100644
> --- a/drivers/gpu/drm/panthor/panthor_fw.h
> +++ b/drivers/gpu/drm/panthor/panthor_fw.h
> @@ -167,10 +167,11 @@ struct panthor_fw_csg_input_iface {
> #define CSG_EP_REQ_TILER(x) (((x) << 16) & GENMASK(19, 16))
> #define CSG_EP_REQ_EXCL_COMPUTE BIT(20)
> #define CSG_EP_REQ_EXCL_FRAGMENT BIT(21)
> -#define CSG_EP_REQ_PRIORITY(x) (((x) << 28) & GENMASK(31, 28))
> #define CSG_EP_REQ_PRIORITY_MASK GENMASK(31, 28)
> +#define CSG_EP_REQ_PRIORITY(x) (((x) << 28) & CSG_EP_REQ_PRIORITY_MASK)
> +#define CSG_EP_REQ_PRIORITY_GET(x) (((x) & CSG_EP_REQ_PRIORITY_MASK) >> 28)
> u32 endpoint_req;
> - u32 reserved2[2];
> + u64 endpoint_req2;
> u64 suspend_buf;
> u64 protm_suspend_buf;
> u32 config;
> @@ -464,6 +465,16 @@ struct panthor_fw_global_iface {
> spin_unlock(&(__iface)->lock); \
> } while (0)
>
> +#define panthor_fw_update_reqs64(__iface, __in_reg, __val, __mask) \
> + do { \
> + u64 __cur_val, __new_val; \
> + spin_lock(&(__iface)->lock); \
> + __cur_val = READ_ONCE((__iface)->input->__in_reg); \
> + __new_val = (__cur_val & ~(__mask)) | ((__val) & (__mask)); \
> + WRITE_ONCE((__iface)->input->__in_reg, __new_val); \
> + spin_unlock(&(__iface)->lock); \
> + } while (0)
> +
> struct panthor_fw_global_iface *
> panthor_fw_get_glb_iface(struct panthor_device *ptdev);
>
> @@ -473,6 +484,16 @@ panthor_fw_get_csg_iface(struct panthor_device *ptdev, u32 csg_slot);
> struct panthor_fw_cs_iface *
> panthor_fw_get_cs_iface(struct panthor_device *ptdev, u32 csg_slot, u32 cs_slot);
>
> +u64 panthor_fw_csg_endpoint_req_get(struct panthor_device *ptdev,
> + struct panthor_fw_csg_iface *csg_iface);
> +
> +void panthor_fw_csg_endpoint_req_set(struct panthor_device *ptdev,
> + struct panthor_fw_csg_iface *csg_iface, u64 value);
> +
> +void panthor_fw_csg_endpoint_req_update(struct panthor_device *ptdev,
> + struct panthor_fw_csg_iface *csg_iface, u64 value,
> + u64 mask);
> +
> int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_id, u32 req_mask,
> u32 *acked, u32 timeout_ms);
>
> diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
> index 0cc9055f4ee5..d6f5efc10312 100644
> --- a/drivers/gpu/drm/panthor/panthor_sched.c
> +++ b/drivers/gpu/drm/panthor/panthor_sched.c
> @@ -1139,11 +1139,13 @@ csg_slot_sync_priority_locked(struct panthor_device *ptdev, u32 csg_id)
> {
> struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id];
> struct panthor_fw_csg_iface *csg_iface;
> + u64 endpoint_req;
>
> lockdep_assert_held(&ptdev->scheduler->lock);
>
> csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id);
> - csg_slot->priority = (csg_iface->input->endpoint_req & CSG_EP_REQ_PRIORITY_MASK) >> 28;
> + endpoint_req = panthor_fw_csg_endpoint_req_get(ptdev, csg_iface);
> + csg_slot->priority = CSG_EP_REQ_PRIORITY_GET(endpoint_req);
> }
>
> /**
> @@ -1303,6 +1305,7 @@ csg_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 priority)
> struct panthor_csg_slot *csg_slot;
> struct panthor_group *group;
> u32 queue_mask = 0, i;
> + u64 endpoint_req;
>
> lockdep_assert_held(&ptdev->scheduler->lock);
>
> @@ -1329,10 +1332,12 @@ csg_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 priority)
> csg_iface->input->allow_compute = group->compute_core_mask;
> csg_iface->input->allow_fragment = group->fragment_core_mask;
> csg_iface->input->allow_other = group->tiler_core_mask;
> - csg_iface->input->endpoint_req = CSG_EP_REQ_COMPUTE(group->max_compute_cores) |
> - CSG_EP_REQ_FRAGMENT(group->max_fragment_cores) |
> - CSG_EP_REQ_TILER(group->max_tiler_cores) |
> - CSG_EP_REQ_PRIORITY(priority);
> + endpoint_req = CSG_EP_REQ_COMPUTE(group->max_compute_cores) |
> + CSG_EP_REQ_FRAGMENT(group->max_fragment_cores) |
> + CSG_EP_REQ_TILER(group->max_tiler_cores) |
> + CSG_EP_REQ_PRIORITY(priority);
> + panthor_fw_csg_endpoint_req_set(ptdev, csg_iface, endpoint_req);
> +
> csg_iface->input->config = panthor_vm_as(group->vm);
>
> if (group->suspend_buf)
> @@ -2230,9 +2235,9 @@ tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_ctx *c
> continue;
> }
>
> - panthor_fw_update_reqs(csg_iface, endpoint_req,
> - CSG_EP_REQ_PRIORITY(new_csg_prio),
> - CSG_EP_REQ_PRIORITY_MASK);
> + panthor_fw_csg_endpoint_req_update(ptdev, csg_iface,
> + CSG_EP_REQ_PRIORITY(new_csg_prio),
> + CSG_EP_REQ_PRIORITY_MASK);
> csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id,
> csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG,
> CSG_ENDPOINT_CONFIG);
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 8/8] drm/panthor: Add support for Mali-G1 GPUs
2025-10-27 16:13 ` [PATCH v3 8/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
@ 2025-11-07 11:00 ` Steven Price
0 siblings, 0 replies; 19+ messages in thread
From: Steven Price @ 2025-11-07 11:00 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 16:13, Karunika Choo wrote:
> Add support for Mali-G1 GPUs (CSF architecture v14), introducing a new
> panthor_hw_arch_v14 entry with reset and L2 power management operations
> via the PWR_CONTROL block.
>
> Mali-G1 introduces a dedicated PWR_CONTROL block for managing resets and
> power domains. panthor_gpu_info_init() is updated to use this block for
> L2, tiler, and shader domain present register reads.
>
> Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
> ---
> v3:
> * Fixed some includes.
> v2:
> * Removed feature bits usage.
> * Check panthor_hw_has_pwr_ctrl() to read the correct *_PRESENT
> registers instead of reading reserved registers on newer GPUs.
> ---
> drivers/gpu/drm/panthor/panthor_fw.c | 1 +
> drivers/gpu/drm/panthor/panthor_hw.c | 35 ++++++++++++++++++++++++----
> 2 files changed, 32 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
> index 2ab974c9a09d..9450a917e66b 100644
> --- a/drivers/gpu/drm/panthor/panthor_fw.c
> +++ b/drivers/gpu/drm/panthor/panthor_fw.c
> @@ -1501,3 +1501,4 @@ MODULE_FIRMWARE("arm/mali/arch10.12/mali_csffw.bin");
> MODULE_FIRMWARE("arm/mali/arch11.8/mali_csffw.bin");
> MODULE_FIRMWARE("arm/mali/arch12.8/mali_csffw.bin");
> MODULE_FIRMWARE("arm/mali/arch13.8/mali_csffw.bin");
> +MODULE_FIRMWARE("arm/mali/arch14.8/mali_csffw.bin");
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 1041201d83e5..263d4a525686 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -4,6 +4,7 @@
> #include "panthor_device.h"
> #include "panthor_gpu.h"
> #include "panthor_hw.h"
> +#include "panthor_pwr.h"
>
> #define GPU_PROD_ID_MAKE(arch_major, prod_major) \
> (((arch_major) << 24) | (prod_major))
> @@ -28,12 +29,25 @@ static struct panthor_hw panthor_hw_arch_v10 = {
> },
> };
>
> +static struct panthor_hw panthor_hw_arch_v14 = {
> + .ops = {
> + .soft_reset = panthor_pwr_reset_soft,
> + .l2_power_off = panthor_pwr_l2_power_off,
> + .l2_power_on = panthor_pwr_l2_power_on,
> + },
> +};
> +
> static struct panthor_hw_entry panthor_hw_match[] = {
> {
> .arch_min = 10,
> .arch_max = 13,
> .hwdev = &panthor_hw_arch_v10,
> },
> + {
> + .arch_min = 14,
> + .arch_max = 14,
> + .hwdev = &panthor_hw_arch_v14,
> + },
> };
>
> static char *get_gpu_model_name(struct panthor_device *ptdev)
> @@ -81,6 +95,12 @@ static char *get_gpu_model_name(struct panthor_device *ptdev)
> fallthrough;
> case GPU_PROD_ID_MAKE(13, 1):
> return "Mali-G625";
> + case GPU_PROD_ID_MAKE(14, 0):
> + return "Mali-G1-Ultra";
> + case GPU_PROD_ID_MAKE(14, 1):
> + return "Mali-G1-Premium";
> + case GPU_PROD_ID_MAKE(14, 3):
> + return "Mali-G1-Pro";
> }
>
> return "(Unknown Mali GPU)";
> @@ -107,12 +127,19 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev)
>
> ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT);
>
> - ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT);
> - ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
> - ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
> -
> /* Introduced in arch 11.x */
> ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES);
> +
> + if (panthor_hw_has_pwr_ctrl(ptdev)) {
> + /* Introduced in arch 14.x */
> + ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT);
> + ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT);
> + ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT);
> + } else {
> + ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT);
> + ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
> + ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
> + }
> }
>
> static void panthor_hw_info_init(struct panthor_device *ptdev)
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (7 preceding siblings ...)
2025-10-27 16:13 ` [PATCH v3 8/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
@ 2025-11-07 11:05 ` Boris Brezillon
8 siblings, 0 replies; 19+ messages in thread
From: Boris Brezillon @ 2025-11-07 11:05 UTC (permalink / raw)
To: Karunika Choo
Cc: dri-devel, nd, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On Mon, 27 Oct 2025 16:13:26 +0000
Karunika Choo <karunika.choo@arm.com> wrote:
> This patch series extends the Panthor driver with basic support for
> Mali-G1 GPUs.
>
> The v14 architecture introduces several hardware and register-level
> changes compared to prior GPUs. This series adds the necessary
> architecture-specific support infrastructure, power control and reset
> handling for Mali-G1 GPUs.
>
> Patch Breakdown:
> [Patch 1-2]: Refactor panthor_hw to introduce architecture-specific
> hooks and abstractions to support the v14 architecture.
> These patches introduce architecture-specific HW binding
> for function pointers.
> [Patch 3-5]: Adds basic L2 power on/off and soft reset support for the
> PWR_CONTROL block introduced in v14.
> [Patch 6]: Update MCU halt and warm boot operations to reflect the
> GLB_REQ.STATE changes in v14. This ensures that the MCU is
> properly halted and the correct operations are performed
> on warm boot depending on the FW version.
> [Patch 7]: Align endpoint_req with changes introduced in v14, where
> the register is widened to 64-bit and shifed down by
> 4-bytes. This patch adds the necessary infrastructure to
> discern the correct endpoint_req register to use.
> [Patch 8]: Enables Mali-G1 support on Panthor by adding HW bindings
> for v14 architecture, product names and path to FW binary.
>
> v3:
> * Updated include logic to enable static inline functions in
> panthor_hw.h for function pointers and feature checks.
> * Fixed missed replacement of CSF_IFACE_VERSION check with
> panthor_fw_has_glb_state() check.
> * Link to v2: https://lore.kernel.org/all/20251024202117.3241292-1-karunika.choo@arm.com/
Didn't thoroughly review the patchset, but I'm happy with the feature
checking changes, and I see that Steve has reviewed the whole thing, so
feel free to stick my
Acked-by: Boris Brezillon <boris.brezillon@collabora.com>
> v2:
> * Merged GPU_ID refactoring patch with the arch-specific panthor_hw
> binding patch (formerly PATCH 01/10 and PATCH 02/10).
> * Dropped panthor_hw feature bitmap patch in favor of functions that
> performs the relevant architecture version checks.
> * Fixed kernel test bot warnings.
> * Replaced function pointer accessor MACROs with static inline
> functions.
> * Refined power control logic, removed unnecessary checks and redundant
> stubs.
> * Replaced explicit CSG_IFACE_VERSION checks with functions describing
> the feature being checked for.
> * General readability improvements, more consistent error handling,
> behaviour clarifications, and formatting fixes.
> * Link to v1: https://lore.kernel.org/all/20251014094337.1009601-1-karunika.choo@arm.com/
>
> Karunika Choo (8):
> drm/panthor: Add arch-specific panthor_hw binding
> drm/panthor: Add architecture-specific function operations
> drm/panthor: Introduce panthor_pwr API and power control framework
> drm/panthor: Implement L2 power on/off via PWR_CONTROL
> drm/panthor: Implement soft reset via PWR_CONTROL
> drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
> drm/panthor: Support 64-bit endpoint_req register for Mali-G1
> drm/panthor: Add support for Mali-G1 GPUs
>
> drivers/gpu/drm/panthor/Makefile | 1 +
> drivers/gpu/drm/panthor/panthor_device.c | 18 +-
> drivers/gpu/drm/panthor/panthor_device.h | 7 +
> drivers/gpu/drm/panthor/panthor_fw.c | 131 +++++-
> drivers/gpu/drm/panthor/panthor_fw.h | 32 +-
> drivers/gpu/drm/panthor/panthor_gpu.c | 12 +-
> drivers/gpu/drm/panthor/panthor_gpu.h | 1 +
> drivers/gpu/drm/panthor/panthor_hw.c | 108 ++++-
> drivers/gpu/drm/panthor/panthor_hw.h | 47 +-
> drivers/gpu/drm/panthor/panthor_pwr.c | 548 +++++++++++++++++++++++
> drivers/gpu/drm/panthor/panthor_pwr.h | 23 +
> drivers/gpu/drm/panthor/panthor_regs.h | 79 ++++
> drivers/gpu/drm/panthor/panthor_sched.c | 21 +-
> 13 files changed, 987 insertions(+), 41 deletions(-)
> create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.c
> create mode 100644 drivers/gpu/drm/panthor/panthor_pwr.h
>
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-11-07 11:05 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-27 16:13 [PATCH v3 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-10-27 16:13 ` [PATCH v3 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
2025-10-28 16:16 ` Liviu Dudau
2025-11-07 9:24 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 2/8] drm/panthor: Add architecture-specific function operations Karunika Choo
2025-11-07 9:48 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
2025-11-07 10:07 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
2025-11-07 10:18 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 5/8] drm/panthor: Implement soft reset " Karunika Choo
2025-11-07 10:26 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
2025-11-07 10:50 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1 Karunika Choo
2025-11-07 10:59 ` Steven Price
2025-10-27 16:13 ` [PATCH v3 8/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-11-07 11:00 ` Steven Price
2025-11-07 11:05 ` [PATCH v3 0/8] " Boris Brezillon
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.