* [PATCH v2 1/8] drm/panthor: Add arch-specific panthor_hw binding
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-24 20:21 ` [PATCH v2 2/8] drm/panthor: Add architecture-specific function operations Karunika Choo
` (6 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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] 17+ messages in thread* [PATCH v2 2/8] drm/panthor: Add architecture-specific function operations
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-10-24 20:21 ` [PATCH v2 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-24 20:21 ` [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
` (5 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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>
---
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 | 5 ++---
drivers/gpu/drm/panthor/panthor_device.h | 18 +++++++++++++++++-
drivers/gpu/drm/panthor/panthor_fw.c | 4 ++--
drivers/gpu/drm/panthor/panthor_gpu.c | 11 ++++++++---
drivers/gpu/drm/panthor/panthor_gpu.h | 1 +
drivers/gpu/drm/panthor/panthor_hw.c | 10 ++++++++--
drivers/gpu/drm/panthor/panthor_hw.h | 18 ++++++++++++++++++
7 files changed, 56 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index 81df49880bd8..224a9237a2cc 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -18,7 +18,6 @@
#include "panthor_device.h"
#include "panthor_fw.h"
#include "panthor_gpu.h"
-#include "panthor_hw.h"
#include "panthor_mmu.h"
#include "panthor_regs.h"
#include "panthor_sched.h"
@@ -141,8 +140,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_device_soft_reset(ptdev);
+ panthor_device_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..2026cc6532ce 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -20,13 +20,14 @@
#include <drm/gpu_scheduler.h>
#include <drm/panthor_drm.h>
+#include "panthor_hw.h"
+
struct panthor_csf;
struct panthor_csf_ctx;
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;
@@ -532,4 +533,19 @@ static inline u64 gpu_read64_counter(struct panthor_device *ptdev, u32 reg)
read_poll_timeout(gpu_read64_relaxed, val, cond, delay_us, timeout_us, \
false, dev, reg)
+static inline int panthor_device_soft_reset(struct panthor_device *ptdev)
+{
+ return ptdev->hw->ops.soft_reset(ptdev);
+}
+
+static inline int panthor_device_l2_power_on(struct panthor_device *ptdev)
+{
+ return ptdev->hw->ops.l2_power_on(ptdev);
+}
+
+static inline void panthor_device_l2_power_off(struct panthor_device *ptdev)
+{
+ ptdev->hw->ops.l2_power_off(ptdev);
+}
+
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 9bf06e55eaee..6b91c3cb6678 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -1184,7 +1184,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_device_l2_power_off(ptdev);
}
/**
@@ -1363,7 +1363,7 @@ int panthor_fw_init(struct panthor_device *ptdev)
return ret;
}
- ret = panthor_gpu_l2_power_on(ptdev);
+ ret = panthor_device_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..f6181462047f 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -218,6 +218,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 +349,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_device_soft_reset(ptdev);
else
- panthor_gpu_power_off(ptdev, L2, 1, 20000);
+ panthor_device_l2_power_off(ptdev);
panthor_gpu_irq_suspend(&ptdev->gpu->irq);
}
@@ -361,6 +366,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_device_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..092962db5ccd 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -2,7 +2,7 @@
/* Copyright 2025 ARM Limited. All rights reserved. */
#include "panthor_device.h"
-#include "panthor_hw.h"
+#include "panthor_gpu.h"
#include "panthor_regs.h"
#define GPU_PROD_ID_MAKE(arch_major, prod_major) \
@@ -20,7 +20,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..2665d6dde2e3 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -6,10 +6,28 @@
struct panthor_device;
+/**
+ * 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);
--
2.49.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
2025-10-24 20:21 ` [PATCH v2 1/8] drm/panthor: Add arch-specific panthor_hw binding Karunika Choo
2025-10-24 20:21 ` [PATCH v2 2/8] drm/panthor: Add architecture-specific function operations Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-26 8:13 ` Boris Brezillon
2025-10-24 20:21 ` [PATCH v2 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
` (4 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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>
---
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 | 5 +
drivers/gpu/drm/panthor/panthor_hw.h | 2 +
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, 240 insertions(+), 1 deletion(-)
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 224a9237a2cc..9d2adcb5431d 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -19,6 +19,7 @@
#include "panthor_fw.h"
#include "panthor_gpu.h"
#include "panthor_mmu.h"
+#include "panthor_pwr.h"
#include "panthor_regs.h"
#include "panthor_sched.h"
@@ -101,6 +102,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);
@@ -248,10 +250,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;
@@ -292,6 +298,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;
@@ -445,6 +454,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);
@@ -454,6 +464,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;
}
@@ -567,6 +578,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 2026cc6532ce..3231c8154e60 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -32,6 +32,7 @@ struct panthor_job;
struct panthor_mmu;
struct panthor_fw;
struct panthor_perfcnt;
+struct panthor_pwr;
struct panthor_vm;
struct panthor_vm_pool;
@@ -127,6 +128,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 092962db5ccd..09aef34a6ce7 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -192,3 +192,8 @@ int panthor_hw_init(struct panthor_device *ptdev)
return 0;
}
+
+bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
+{
+ return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
+}
diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
index 2665d6dde2e3..4c71f27d1c0b 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -32,4 +32,6 @@ struct panthor_hw {
int panthor_hw_init(struct panthor_device *ptdev);
+bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev);
+
#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] 17+ messages in thread* Re: [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-24 20:21 ` [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
@ 2025-10-26 8:13 ` Boris Brezillon
2025-10-27 10:36 ` Karunika Choo
0 siblings, 1 reply; 17+ messages in thread
From: Boris Brezillon @ 2025-10-26 8:13 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 Fri, 24 Oct 2025 21:21:12 +0100
Karunika Choo <karunika.choo@arm.com> wrote:
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> index 092962db5ccd..09aef34a6ce7 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> @@ -192,3 +192,8 @@ int panthor_hw_init(struct panthor_device *ptdev)
>
> return 0;
> }
> +
> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
> +{
> + return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
> +}
> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
> index 2665d6dde2e3..4c71f27d1c0b 100644
> --- a/drivers/gpu/drm/panthor/panthor_hw.h
> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
> @@ -32,4 +32,6 @@ struct panthor_hw {
>
> int panthor_hw_init(struct panthor_device *ptdev);
>
> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev);
Let's make this a static inline function so the compiler can inline its
content at compile time.
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-26 8:13 ` Boris Brezillon
@ 2025-10-27 10:36 ` Karunika Choo
2025-10-27 11:36 ` Boris Brezillon
0 siblings, 1 reply; 17+ messages in thread
From: Karunika Choo @ 2025-10-27 10:36 UTC (permalink / raw)
To: Boris Brezillon
Cc: dri-devel, nd, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 26/10/2025 08:13, Boris Brezillon wrote:
> On Fri, 24 Oct 2025 21:21:12 +0100
> Karunika Choo <karunika.choo@arm.com> wrote:
>> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
>> index 092962db5ccd..09aef34a6ce7 100644
>> --- a/drivers/gpu/drm/panthor/panthor_hw.c
>> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
>> @@ -192,3 +192,8 @@ int panthor_hw_init(struct panthor_device *ptdev)
>>
>> return 0;
>> }
>> +
>> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
>> +{
>> + return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
>> +}
>> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
>> index 2665d6dde2e3..4c71f27d1c0b 100644
>> --- a/drivers/gpu/drm/panthor/panthor_hw.h
>> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
>> @@ -32,4 +32,6 @@ struct panthor_hw {
>>
>> int panthor_hw_init(struct panthor_device *ptdev);
>>
>> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev);
>
> Let's make this a static inline function so the compiler can inline its
> content at compile time.
>
I wonder if making it static inline is a good idea. We will need to move
this function into panthor_device.h to be able to do so as we need to
access the panthor_device structure. Would this still be desirable?
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-27 10:36 ` Karunika Choo
@ 2025-10-27 11:36 ` Boris Brezillon
2025-10-27 14:12 ` Karunika Choo
0 siblings, 1 reply; 17+ messages in thread
From: Boris Brezillon @ 2025-10-27 11:36 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 10:36:13 +0000
Karunika Choo <karunika.choo@arm.com> wrote:
> On 26/10/2025 08:13, Boris Brezillon wrote:
> > On Fri, 24 Oct 2025 21:21:12 +0100
> > Karunika Choo <karunika.choo@arm.com> wrote:
> >> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
> >> index 092962db5ccd..09aef34a6ce7 100644
> >> --- a/drivers/gpu/drm/panthor/panthor_hw.c
> >> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
> >> @@ -192,3 +192,8 @@ int panthor_hw_init(struct panthor_device *ptdev)
> >>
> >> return 0;
> >> }
> >> +
> >> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
> >> +{
> >> + return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
> >> +}
> >> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
> >> index 2665d6dde2e3..4c71f27d1c0b 100644
> >> --- a/drivers/gpu/drm/panthor/panthor_hw.h
> >> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
> >> @@ -32,4 +32,6 @@ struct panthor_hw {
> >>
> >> int panthor_hw_init(struct panthor_device *ptdev);
> >>
> >> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev);
> >
> > Let's make this a static inline function so the compiler can inline its
> > content at compile time.
> >
>
> I wonder if making it static inline is a good idea. We will need to move
> this function into panthor_device.h to be able to do so as we need to
> access the panthor_device structure. Would this still be desirable?
Can't we just include panthor_device.h from panthor_hw.h instead? As
far as I can tell, panthor_device.h doesn't include panthor_hw.h, so we
should be fine.
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework
2025-10-27 11:36 ` Boris Brezillon
@ 2025-10-27 14:12 ` Karunika Choo
0 siblings, 0 replies; 17+ messages in thread
From: Karunika Choo @ 2025-10-27 14:12 UTC (permalink / raw)
To: Boris Brezillon
Cc: dri-devel, nd, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 27/10/2025 11:36, Boris Brezillon wrote:
> On Mon, 27 Oct 2025 10:36:13 +0000
> Karunika Choo <karunika.choo@arm.com> wrote:
>
>> On 26/10/2025 08:13, Boris Brezillon wrote:
>>> On Fri, 24 Oct 2025 21:21:12 +0100
>>> Karunika Choo <karunika.choo@arm.com> wrote:
>>>> diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c
>>>> index 092962db5ccd..09aef34a6ce7 100644
>>>> --- a/drivers/gpu/drm/panthor/panthor_hw.c
>>>> +++ b/drivers/gpu/drm/panthor/panthor_hw.c
>>>> @@ -192,3 +192,8 @@ int panthor_hw_init(struct panthor_device *ptdev)
>>>>
>>>> return 0;
>>>> }
>>>> +
>>>> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
>>>> +{
>>>> + return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
>>>> +}
>>>> diff --git a/drivers/gpu/drm/panthor/panthor_hw.h b/drivers/gpu/drm/panthor/panthor_hw.h
>>>> index 2665d6dde2e3..4c71f27d1c0b 100644
>>>> --- a/drivers/gpu/drm/panthor/panthor_hw.h
>>>> +++ b/drivers/gpu/drm/panthor/panthor_hw.h
>>>> @@ -32,4 +32,6 @@ struct panthor_hw {
>>>>
>>>> int panthor_hw_init(struct panthor_device *ptdev);
>>>>
>>>> +bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev);
>>>
>>> Let's make this a static inline function so the compiler can inline its
>>> content at compile time.
>>>
>>
>> I wonder if making it static inline is a good idea. We will need to move
>> this function into panthor_device.h to be able to do so as we need to
>> access the panthor_device structure. Would this still be desirable?
>
> Can't we just include panthor_device.h from panthor_hw.h instead? As
> far as I can tell, panthor_device.h doesn't include panthor_hw.h, so we
> should be fine.
v2 changed this, but let me see if I can rework these to enable both
your's and Steve's suggestions.
Kind regards,
Karunika Choo
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (2 preceding siblings ...)
2025-10-24 20:21 ` [PATCH v2 3/8] drm/panthor: Introduce panthor_pwr API and power control framework Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-27 8:50 ` Erik Faye-Lund
2025-10-24 20:21 ` [PATCH v2 5/8] drm/panthor: Implement soft reset " Karunika Choo
` (3 subsequent siblings)
7 siblings, 1 reply; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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] 17+ messages in thread* Re: [PATCH v2 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL
2025-10-24 20:21 ` [PATCH v2 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
@ 2025-10-27 8:50 ` Erik Faye-Lund
0 siblings, 0 replies; 17+ messages in thread
From: Erik Faye-Lund @ 2025-10-27 8:50 UTC (permalink / raw)
To: Karunika Choo, dri-devel
Cc: nd, Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On Fri, 2025-10-24 at 21:21 +0100, 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>
> ---
> 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)
This seems out of place in this commit, which is about power stuff...
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 5/8] drm/panthor: Implement soft reset via PWR_CONTROL
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (3 preceding siblings ...)
2025-10-24 20:21 ` [PATCH v2 4/8] drm/panthor: Implement L2 power on/off via PWR_CONTROL Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-24 20:21 ` [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
` (2 subsequent siblings)
7 siblings, 0 replies; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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] 17+ messages in thread* [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (4 preceding siblings ...)
2025-10-24 20:21 ` [PATCH v2 5/8] drm/panthor: Implement soft reset " Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-26 8:27 ` Boris Brezillon
2025-10-24 20:21 ` [PATCH v2 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1 Karunika Choo
2025-10-24 20:21 ` [PATCH v2 8/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
7 siblings, 1 reply; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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>
---
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 6b91c3cb6678..78f884ccb8b0 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -32,6 +32,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.
@@ -316,6 +317,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.
@@ -995,6 +1003,9 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
GLB_IDLE_EN |
GLB_IDLE;
+ if (glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0))
+ 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 |
@@ -1068,6 +1079,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.
@@ -1084,19 +1143,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);
}
@@ -1124,14 +1177,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);
@@ -1169,6 +1222,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] 17+ messages in thread* Re: [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
2025-10-24 20:21 ` [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
@ 2025-10-26 8:27 ` Boris Brezillon
2025-10-27 10:43 ` Karunika Choo
0 siblings, 1 reply; 17+ messages in thread
From: Boris Brezillon @ 2025-10-26 8:27 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 Fri, 24 Oct 2025 21:21:15 +0100
Karunika Choo <karunika.choo@arm.com> wrote:
> +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);
> +}
It's okay for now, but if we start having more of these, we probably
want to automate the generation of those has_<featurex>() helpers with
something like:
#define FW_FEATURE(feat_name, major, minor) \
static bool panthor_fw_has_ ## feat_name(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(major, minor, 0); \
}
Same goes for the HW features BTW.
> +
> /**
> * panthor_fw_conv_timeout() - Convert a timeout into a cycle-count
> * @ptdev: Device.
> @@ -995,6 +1003,9 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
> GLB_IDLE_EN |
> GLB_IDLE;
>
> + if (glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0))
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 |
> @@ -1068,6 +1079,54 @@ static void panthor_fw_stop(struct panthor_device *ptdev)
> drm_err(&ptdev->base, "Failed to stop MCU");
> }
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
2025-10-26 8:27 ` Boris Brezillon
@ 2025-10-27 10:43 ` Karunika Choo
2025-10-27 11:31 ` Boris Brezillon
0 siblings, 1 reply; 17+ messages in thread
From: Karunika Choo @ 2025-10-27 10:43 UTC (permalink / raw)
To: Boris Brezillon
Cc: dri-devel, nd, Steven Price, Liviu Dudau, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
linux-kernel
On 26/10/2025 08:27, Boris Brezillon wrote:
> On Fri, 24 Oct 2025 21:21:15 +0100
> Karunika Choo <karunika.choo@arm.com> wrote:
>
>> +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);
>> +}
>
> It's okay for now, but if we start having more of these, we probably
> want to automate the generation of those has_<featurex>() helpers with
> something like:
>
> #define FW_FEATURE(feat_name, major, minor) \
> static bool panthor_fw_has_ ## feat_name(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(major, minor, 0); \
> }
>
> Same goes for the HW features BTW.
>
I wonder if at that point, would a bitmask as previously proposed be a
cleaner solution? I have a minor bone to pick with MACROs that generate
functions as they make finding its definition unnecessarily complicated
and obtuse. Not to mention if the conditions for a feature changes and
is disjoint from all the others, updating the macro to handle these
would cause additional churn that I would really hope to avoid.
>> +
>> /**
>> * panthor_fw_conv_timeout() - Convert a timeout into a cycle-count
>> * @ptdev: Device.
>> @@ -995,6 +1003,9 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev)
>> GLB_IDLE_EN |
>> GLB_IDLE;
>>
>> + if (glb_iface->control->version >= CSF_IFACE_VERSION(4, 1, 0))
>
> if (panthor_fw_has_glb_state(ptdev))
>
Thanks for catching this. Will fix in v3.
Kind regards,
Karunika Choo
>> + 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 |
>> @@ -1068,6 +1079,54 @@ static void panthor_fw_stop(struct panthor_device *ptdev)
>> drm_err(&ptdev->base, "Failed to stop MCU");
>> }
>
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs
2025-10-27 10:43 ` Karunika Choo
@ 2025-10-27 11:31 ` Boris Brezillon
0 siblings, 0 replies; 17+ messages in thread
From: Boris Brezillon @ 2025-10-27 11:31 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 10:43:42 +0000
Karunika Choo <karunika.choo@arm.com> wrote:
> On 26/10/2025 08:27, Boris Brezillon wrote:
> > On Fri, 24 Oct 2025 21:21:15 +0100
> > Karunika Choo <karunika.choo@arm.com> wrote:
> >
> >> +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);
> >> +}
> >
> > It's okay for now, but if we start having more of these, we probably
> > want to automate the generation of those has_<featurex>() helpers with
> > something like:
> >
> > #define FW_FEATURE(feat_name, major, minor) \
> > static bool panthor_fw_has_ ## feat_name(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(major, minor, 0); \
> > }
> >
> > Same goes for the HW features BTW.
> >
>
> I wonder if at that point, would a bitmask as previously proposed be a
> cleaner solution? I have a minor bone to pick with MACROs that generate
> functions as they make finding its definition unnecessarily complicated
> and obtuse. Not to mention if the conditions for a feature changes and
> is disjoint from all the others, updating the macro to handle these
> would cause additional churn that I would really hope to avoid.
Let's do without the macros for now.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (5 preceding siblings ...)
2025-10-24 20:21 ` [PATCH v2 6/8] drm/panthor: Support GLB_REQ.STATE field for Mali-G1 GPUs Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
2025-10-24 20:21 ` [PATCH v2 8/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
7 siblings, 0 replies; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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 78f884ccb8b0..9ba10ab1d7c0 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -324,6 +324,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] 17+ messages in thread* [PATCH v2 8/8] drm/panthor: Add support for Mali-G1 GPUs
2025-10-24 20:21 [PATCH v2 0/8] drm/panthor: Add support for Mali-G1 GPUs Karunika Choo
` (6 preceding siblings ...)
2025-10-24 20:21 ` [PATCH v2 7/8] drm/panthor: Support 64-bit endpoint_req register for Mali-G1 Karunika Choo
@ 2025-10-24 20:21 ` Karunika Choo
7 siblings, 0 replies; 17+ messages in thread
From: Karunika Choo @ 2025-10-24 20:21 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>
---
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 9ba10ab1d7c0..031d23166c18 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -1500,3 +1500,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 09aef34a6ce7..29c7a6e60300 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.c
+++ b/drivers/gpu/drm/panthor/panthor_hw.c
@@ -3,6 +3,7 @@
#include "panthor_device.h"
#include "panthor_gpu.h"
+#include "panthor_pwr.h"
#include "panthor_regs.h"
#define GPU_PROD_ID_MAKE(arch_major, 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] 17+ messages in thread