]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/panthor: Introduce panthor_pwr API and power control framework
authorKarunika Choo <karunika.choo@arm.com>
Tue, 25 Nov 2025 12:55:43 +0000 (12:55 +0000)
committerBoris Brezillon <boris.brezillon@collabora.com>
Wed, 26 Nov 2025 09:56:18 +0000 (10:56 +0100)
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.

Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Karunika Choo <karunika.choo@arm.com>
Link: https://patch.msgid.link/20251125125548.3282320-4-karunika.choo@arm.com
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
drivers/gpu/drm/panthor/Makefile
drivers/gpu/drm/panthor/panthor_device.c
drivers/gpu/drm/panthor/panthor_device.h
drivers/gpu/drm/panthor/panthor_hw.h
drivers/gpu/drm/panthor/panthor_pwr.c [new file with mode: 0644]
drivers/gpu/drm/panthor/panthor_pwr.h [new file with mode: 0644]
drivers/gpu/drm/panthor/panthor_regs.h

index 02db21748c125688d2ef20ed254b5ebd7ff642e4..753a32c446df0ffdae264cfaed309f0ea8bef533 100644 (file)
@@ -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
index 0ecf552caa5cd6c2366fb1fb4d4759b97385847f..e133b1e0ad6de0640f0fa2692ba71253c44df322 100644 (file)
@@ -21,6 +21,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"
 
@@ -113,6 +114,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);
@@ -268,10 +270,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;
@@ -312,6 +318,9 @@ err_unplug_mmu:
 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;
@@ -465,6 +474,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);
 
@@ -474,6 +484,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;
 }
 
@@ -587,6 +598,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);
        }
 
index f0b143732ea075a3039d636346508c50f694395d..f35e52b9546ace20e7e2d2e059bb027746ed0f41 100644 (file)
@@ -29,6 +29,7 @@ struct panthor_job;
 struct panthor_mmu;
 struct panthor_fw;
 struct panthor_perfcnt;
+struct panthor_pwr;
 struct panthor_vm;
 struct panthor_vm_pool;
 
@@ -138,6 +139,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;
 
index 64616caa6f05e6f0f7c8754fe0e6d886400696ed..56c68c1e9c26159dd0519730445ad0b3891d759c 100644 (file)
@@ -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 (file)
index 0000000..66dc72b
--- /dev/null
@@ -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 (file)
index 0000000..b325e5b
--- /dev/null
@@ -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__ */
index 8fa69f33e911ebc76e4ab3cc3d1698445f461c16..e47a89f249002802dc6f173929fd6a9286201dbd 100644 (file)
 #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