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 <[email protected]>
---
v4:
 * Reintroduced include for panthor_regs.h.
 * Add include for drm_print.h
v3:
 * Turned panthor_hw_has_pwr_ctrl() into a static inline function.
v2:
 * Removed stub functions.
 * Updated BIT() definitions for 64-bit fields to use BIT_U64() to
   address kernel test robot warnings for 32-bit systems.
 * Moved GPU_FEATURES_RAY_TRAVERSAL definition to the next patch where
   it is being used.
 * Drop the use of feature bits in favour of a function that performs a
   GPU_ARCH_MAJOR check instead.
---
 drivers/gpu/drm/panthor/Makefile         |   1 +
 drivers/gpu/drm/panthor/panthor_device.c |  14 ++-
 drivers/gpu/drm/panthor/panthor_device.h |   4 +
 drivers/gpu/drm/panthor/panthor_hw.h     |   6 ++
 drivers/gpu/drm/panthor/panthor_pwr.c    | 121 +++++++++++++++++++++++
 drivers/gpu/drm/panthor/panthor_pwr.h    |  17 ++++
 drivers/gpu/drm/panthor/panthor_regs.h   |  78 +++++++++++++++
 7 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 847dea458682..d3e16da0b24e 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -20,6 +20,7 @@
 #include "panthor_gpu.h"
 #include "panthor_hw.h"
 #include "panthor_mmu.h"
+#include "panthor_pwr.h"
 #include "panthor_regs.h"
 #include "panthor_sched.h"

@@ -102,6 +103,7 @@ void panthor_device_unplug(struct panthor_device *ptdev)
        panthor_fw_unplug(ptdev);
        panthor_mmu_unplug(ptdev);
        panthor_gpu_unplug(ptdev);
+       panthor_pwr_unplug(ptdev);

        pm_runtime_dont_use_autosuspend(ptdev->base.dev);
        pm_runtime_put_sync_suspend(ptdev->base.dev);
@@ -249,10 +251,14 @@ int panthor_device_init(struct panthor_device *ptdev)
        if (ret)
                goto err_rpm_put;

-       ret = panthor_gpu_init(ptdev);
+       ret = panthor_pwr_init(ptdev);
        if (ret)
                goto err_rpm_put;

+       ret = panthor_gpu_init(ptdev);
+       if (ret)
+               goto err_unplug_pwr;
+
        ret = panthor_gpu_coherency_init(ptdev);
        if (ret)
                goto err_unplug_gpu;
@@ -293,6 +299,9 @@ int panthor_device_init(struct panthor_device *ptdev)
 err_unplug_gpu:
        panthor_gpu_unplug(ptdev);

+err_unplug_pwr:
+       panthor_pwr_unplug(ptdev);
+
 err_rpm_put:
        pm_runtime_put_sync_suspend(ptdev->base.dev);
        return ret;
@@ -446,6 +455,7 @@ static int panthor_device_resume_hw_components(struct 
panthor_device *ptdev)
 {
        int ret;

+       panthor_pwr_resume(ptdev);
        panthor_gpu_resume(ptdev);
        panthor_mmu_resume(ptdev);

@@ -455,6 +465,7 @@ static int panthor_device_resume_hw_components(struct 
panthor_device *ptdev)

        panthor_mmu_suspend(ptdev);
        panthor_gpu_suspend(ptdev);
+       panthor_pwr_suspend(ptdev);
        return ret;
 }

@@ -568,6 +579,7 @@ int panthor_device_suspend(struct device *dev)
                panthor_fw_suspend(ptdev);
                panthor_mmu_suspend(ptdev);
                panthor_gpu_suspend(ptdev);
+               panthor_pwr_suspend(ptdev);
                drm_dev_exit(cookie);
        }

diff --git a/drivers/gpu/drm/panthor/panthor_device.h 
b/drivers/gpu/drm/panthor/panthor_device.h
index 1457c1255f1f..05818318e0ba 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -31,6 +31,7 @@ struct panthor_job;
 struct panthor_mmu;
 struct panthor_fw;
 struct panthor_perfcnt;
+struct panthor_pwr;
 struct panthor_vm;
 struct panthor_vm_pool;

@@ -126,6 +127,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.h 
b/drivers/gpu/drm/panthor/panthor_hw.h
index 64616caa6f05..56c68c1e9c26 100644
--- a/drivers/gpu/drm/panthor/panthor_hw.h
+++ b/drivers/gpu/drm/panthor/panthor_hw.h
@@ -5,6 +5,7 @@
 #define __PANTHOR_HW_H__

 #include "panthor_device.h"
+#include "panthor_regs.h"

 /**
  * struct panthor_hw_ops - HW operations that are specific to a GPU
@@ -47,4 +48,9 @@ static inline void panthor_hw_l2_power_off(struct 
panthor_device *ptdev)
        ptdev->hw->ops.l2_power_off(ptdev);
 }

+static inline bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)
+{
+       return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14;
+}
+
 #endif /* __PANTHOR_HW_H__ */
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c 
b/drivers/gpu/drm/panthor/panthor_pwr.c
new file mode 100644
index 000000000000..66dc72b29116
--- /dev/null
+++ b/drivers/gpu/drm/panthor/panthor_pwr.c
@@ -0,0 +1,121 @@
+// 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 <drm/drm_print.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

Reply via email to