Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/panthor: Introduce panthor_pwr API and power control framework

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>

authored by

Karunika Choo and committed by
Boris Brezillon
c27787f2 7d334f5c

+240 -1
+1
drivers/gpu/drm/panthor/Makefile
··· 10 10 panthor_heap.o \ 11 11 panthor_hw.o \ 12 12 panthor_mmu.o \ 13 + panthor_pwr.o \ 13 14 panthor_sched.o 14 15 15 16 obj-$(CONFIG_DRM_PANTHOR) += panthor.o
+13 -1
drivers/gpu/drm/panthor/panthor_device.c
··· 21 21 #include "panthor_gpu.h" 22 22 #include "panthor_hw.h" 23 23 #include "panthor_mmu.h" 24 + #include "panthor_pwr.h" 24 25 #include "panthor_regs.h" 25 26 #include "panthor_sched.h" 26 27 ··· 114 113 panthor_fw_unplug(ptdev); 115 114 panthor_mmu_unplug(ptdev); 116 115 panthor_gpu_unplug(ptdev); 116 + panthor_pwr_unplug(ptdev); 117 117 118 118 pm_runtime_dont_use_autosuspend(ptdev->base.dev); 119 119 pm_runtime_put_sync_suspend(ptdev->base.dev); ··· 270 268 if (ret) 271 269 goto err_rpm_put; 272 270 273 - ret = panthor_gpu_init(ptdev); 271 + ret = panthor_pwr_init(ptdev); 274 272 if (ret) 275 273 goto err_rpm_put; 274 + 275 + ret = panthor_gpu_init(ptdev); 276 + if (ret) 277 + goto err_unplug_pwr; 276 278 277 279 ret = panthor_gpu_coherency_init(ptdev); 278 280 if (ret) ··· 317 311 318 312 err_unplug_gpu: 319 313 panthor_gpu_unplug(ptdev); 314 + 315 + err_unplug_pwr: 316 + panthor_pwr_unplug(ptdev); 320 317 321 318 err_rpm_put: 322 319 pm_runtime_put_sync_suspend(ptdev->base.dev); ··· 474 465 { 475 466 int ret; 476 467 468 + panthor_pwr_resume(ptdev); 477 469 panthor_gpu_resume(ptdev); 478 470 panthor_mmu_resume(ptdev); 479 471 ··· 484 474 485 475 panthor_mmu_suspend(ptdev); 486 476 panthor_gpu_suspend(ptdev); 477 + panthor_pwr_suspend(ptdev); 487 478 return ret; 488 479 } 489 480 ··· 598 587 panthor_fw_suspend(ptdev); 599 588 panthor_mmu_suspend(ptdev); 600 589 panthor_gpu_suspend(ptdev); 590 + panthor_pwr_suspend(ptdev); 601 591 drm_dev_exit(cookie); 602 592 } 603 593
+4
drivers/gpu/drm/panthor/panthor_device.h
··· 29 29 struct panthor_mmu; 30 30 struct panthor_fw; 31 31 struct panthor_perfcnt; 32 + struct panthor_pwr; 32 33 struct panthor_vm; 33 34 struct panthor_vm_pool; 34 35 ··· 138 137 139 138 /** @hw: GPU-specific data. */ 140 139 struct panthor_hw *hw; 140 + 141 + /** @pwr: Power control management data. */ 142 + struct panthor_pwr *pwr; 141 143 142 144 /** @gpu: GPU management data. */ 143 145 struct panthor_gpu *gpu;
+6
drivers/gpu/drm/panthor/panthor_hw.h
··· 5 5 #define __PANTHOR_HW_H__ 6 6 7 7 #include "panthor_device.h" 8 + #include "panthor_regs.h" 8 9 9 10 /** 10 11 * struct panthor_hw_ops - HW operations that are specific to a GPU ··· 46 45 static inline void panthor_hw_l2_power_off(struct panthor_device *ptdev) 47 46 { 48 47 ptdev->hw->ops.l2_power_off(ptdev); 48 + } 49 + 50 + static inline bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev) 51 + { 52 + return GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id) >= 14; 49 53 } 50 54 51 55 #endif /* __PANTHOR_HW_H__ */
+121
drivers/gpu/drm/panthor/panthor_pwr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2025 ARM Limited. All rights reserved. */ 3 + 4 + #include <linux/platform_device.h> 5 + #include <linux/interrupt.h> 6 + #include <linux/iopoll.h> 7 + #include <linux/wait.h> 8 + 9 + #include <drm/drm_managed.h> 10 + #include <drm/drm_print.h> 11 + 12 + #include "panthor_device.h" 13 + #include "panthor_hw.h" 14 + #include "panthor_pwr.h" 15 + #include "panthor_regs.h" 16 + 17 + #define PWR_INTERRUPTS_MASK \ 18 + (PWR_IRQ_POWER_CHANGED_SINGLE | \ 19 + PWR_IRQ_POWER_CHANGED_ALL | \ 20 + PWR_IRQ_DELEGATION_CHANGED | \ 21 + PWR_IRQ_RESET_COMPLETED | \ 22 + PWR_IRQ_RETRACT_COMPLETED | \ 23 + PWR_IRQ_INSPECT_COMPLETED | \ 24 + PWR_IRQ_COMMAND_NOT_ALLOWED | \ 25 + PWR_IRQ_COMMAND_INVALID) 26 + 27 + /** 28 + * struct panthor_pwr - PWR_CONTROL block management data. 29 + */ 30 + struct panthor_pwr { 31 + /** @irq: PWR irq. */ 32 + struct panthor_irq irq; 33 + 34 + /** @reqs_lock: Lock protecting access to pending_reqs. */ 35 + spinlock_t reqs_lock; 36 + 37 + /** @pending_reqs: Pending PWR requests. */ 38 + u32 pending_reqs; 39 + 40 + /** @reqs_acked: PWR request wait queue. */ 41 + wait_queue_head_t reqs_acked; 42 + }; 43 + 44 + static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status) 45 + { 46 + spin_lock(&ptdev->pwr->reqs_lock); 47 + gpu_write(ptdev, PWR_INT_CLEAR, status); 48 + 49 + if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED)) 50 + drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED"); 51 + 52 + if (unlikely(status & PWR_IRQ_COMMAND_INVALID)) 53 + drm_err(&ptdev->base, "PWR_IRQ: COMMAND_INVALID"); 54 + 55 + if (status & ptdev->pwr->pending_reqs) { 56 + ptdev->pwr->pending_reqs &= ~status; 57 + wake_up_all(&ptdev->pwr->reqs_acked); 58 + } 59 + spin_unlock(&ptdev->pwr->reqs_lock); 60 + } 61 + PANTHOR_IRQ_HANDLER(pwr, PWR, panthor_pwr_irq_handler); 62 + 63 + void panthor_pwr_unplug(struct panthor_device *ptdev) 64 + { 65 + unsigned long flags; 66 + 67 + if (!ptdev->pwr) 68 + return; 69 + 70 + /* Make sure the IRQ handler is not running after that point. */ 71 + panthor_pwr_irq_suspend(&ptdev->pwr->irq); 72 + 73 + /* Wake-up all waiters. */ 74 + spin_lock_irqsave(&ptdev->pwr->reqs_lock, flags); 75 + ptdev->pwr->pending_reqs = 0; 76 + wake_up_all(&ptdev->pwr->reqs_acked); 77 + spin_unlock_irqrestore(&ptdev->pwr->reqs_lock, flags); 78 + } 79 + 80 + int panthor_pwr_init(struct panthor_device *ptdev) 81 + { 82 + struct panthor_pwr *pwr; 83 + int err, irq; 84 + 85 + if (!panthor_hw_has_pwr_ctrl(ptdev)) 86 + return 0; 87 + 88 + pwr = drmm_kzalloc(&ptdev->base, sizeof(*pwr), GFP_KERNEL); 89 + if (!pwr) 90 + return -ENOMEM; 91 + 92 + spin_lock_init(&pwr->reqs_lock); 93 + init_waitqueue_head(&pwr->reqs_acked); 94 + ptdev->pwr = pwr; 95 + 96 + irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "gpu"); 97 + if (irq < 0) 98 + return irq; 99 + 100 + err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK); 101 + if (err) 102 + return err; 103 + 104 + return 0; 105 + } 106 + 107 + void panthor_pwr_suspend(struct panthor_device *ptdev) 108 + { 109 + if (!ptdev->pwr) 110 + return; 111 + 112 + panthor_pwr_irq_suspend(&ptdev->pwr->irq); 113 + } 114 + 115 + void panthor_pwr_resume(struct panthor_device *ptdev) 116 + { 117 + if (!ptdev->pwr) 118 + return; 119 + 120 + panthor_pwr_irq_resume(&ptdev->pwr->irq, PWR_INTERRUPTS_MASK); 121 + }
+17
drivers/gpu/drm/panthor/panthor_pwr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2025 ARM Limited. All rights reserved. */ 3 + 4 + #ifndef __PANTHOR_PWR_H__ 5 + #define __PANTHOR_PWR_H__ 6 + 7 + struct panthor_device; 8 + 9 + void panthor_pwr_unplug(struct panthor_device *ptdev); 10 + 11 + int panthor_pwr_init(struct panthor_device *ptdev); 12 + 13 + void panthor_pwr_suspend(struct panthor_device *ptdev); 14 + 15 + void panthor_pwr_resume(struct panthor_device *ptdev); 16 + 17 + #endif /* __PANTHOR_PWR_H__ */
+78
drivers/gpu/drm/panthor/panthor_regs.h
··· 209 209 #define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000)) 210 210 #define CSF_GLB_DOORBELL_ID 0 211 211 212 + /* PWR Control registers */ 213 + 214 + #define PWR_CONTROL_BASE 0x800 215 + #define PWR_CTRL_REG(x) (PWR_CONTROL_BASE + (x)) 216 + 217 + #define PWR_INT_RAWSTAT PWR_CTRL_REG(0x0) 218 + #define PWR_INT_CLEAR PWR_CTRL_REG(0x4) 219 + #define PWR_INT_MASK PWR_CTRL_REG(0x8) 220 + #define PWR_INT_STAT PWR_CTRL_REG(0xc) 221 + #define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0) 222 + #define PWR_IRQ_POWER_CHANGED_ALL BIT(1) 223 + #define PWR_IRQ_DELEGATION_CHANGED BIT(2) 224 + #define PWR_IRQ_RESET_COMPLETED BIT(3) 225 + #define PWR_IRQ_RETRACT_COMPLETED BIT(4) 226 + #define PWR_IRQ_INSPECT_COMPLETED BIT(5) 227 + #define PWR_IRQ_COMMAND_NOT_ALLOWED BIT(30) 228 + #define PWR_IRQ_COMMAND_INVALID BIT(31) 229 + 230 + #define PWR_STATUS PWR_CTRL_REG(0x20) 231 + #define PWR_STATUS_ALLOW_L2 BIT_U64(0) 232 + #define PWR_STATUS_ALLOW_TILER BIT_U64(1) 233 + #define PWR_STATUS_ALLOW_SHADER BIT_U64(8) 234 + #define PWR_STATUS_ALLOW_BASE BIT_U64(14) 235 + #define PWR_STATUS_ALLOW_STACK BIT_U64(15) 236 + #define PWR_STATUS_DOMAIN_ALLOWED(x) BIT_U64(x) 237 + #define PWR_STATUS_DELEGATED_L2 BIT_U64(16) 238 + #define PWR_STATUS_DELEGATED_TILER BIT_U64(17) 239 + #define PWR_STATUS_DELEGATED_SHADER BIT_U64(24) 240 + #define PWR_STATUS_DELEGATED_BASE BIT_U64(30) 241 + #define PWR_STATUS_DELEGATED_STACK BIT_U64(31) 242 + #define PWR_STATUS_DELEGATED_SHIFT 16 243 + #define PWR_STATUS_DOMAIN_DELEGATED(x) BIT_U64((x) + PWR_STATUS_DELEGATED_SHIFT) 244 + #define PWR_STATUS_ALLOW_SOFT_RESET BIT_U64(33) 245 + #define PWR_STATUS_ALLOW_FAST_RESET BIT_U64(34) 246 + #define PWR_STATUS_POWER_PENDING BIT_U64(41) 247 + #define PWR_STATUS_RESET_PENDING BIT_U64(42) 248 + #define PWR_STATUS_RETRACT_PENDING BIT_U64(43) 249 + #define PWR_STATUS_INSPECT_PENDING BIT_U64(44) 250 + 251 + #define PWR_COMMAND PWR_CTRL_REG(0x28) 252 + #define PWR_COMMAND_POWER_UP 0x10 253 + #define PWR_COMMAND_POWER_DOWN 0x11 254 + #define PWR_COMMAND_DELEGATE 0x20 255 + #define PWR_COMMAND_RETRACT 0x21 256 + #define PWR_COMMAND_RESET_SOFT 0x31 257 + #define PWR_COMMAND_RESET_FAST 0x32 258 + #define PWR_COMMAND_INSPECT 0xF0 259 + #define PWR_COMMAND_DOMAIN_L2 0 260 + #define PWR_COMMAND_DOMAIN_TILER 1 261 + #define PWR_COMMAND_DOMAIN_SHADER 8 262 + #define PWR_COMMAND_DOMAIN_BASE 14 263 + #define PWR_COMMAND_DOMAIN_STACK 15 264 + #define PWR_COMMAND_SUBDOMAIN_RTU BIT(0) 265 + #define PWR_COMMAND_DEF(cmd, domain, subdomain) \ 266 + (((subdomain) << 16) | ((domain) << 8) | (cmd)) 267 + 268 + #define PWR_CMDARG PWR_CTRL_REG(0x30) 269 + 270 + #define PWR_L2_PRESENT PWR_CTRL_REG(0x100) 271 + #define PWR_L2_READY PWR_CTRL_REG(0x108) 272 + #define PWR_L2_PWRTRANS PWR_CTRL_REG(0x110) 273 + #define PWR_L2_PWRACTIVE PWR_CTRL_REG(0x118) 274 + #define PWR_TILER_PRESENT PWR_CTRL_REG(0x140) 275 + #define PWR_TILER_READY PWR_CTRL_REG(0x148) 276 + #define PWR_TILER_PWRTRANS PWR_CTRL_REG(0x150) 277 + #define PWR_TILER_PWRACTIVE PWR_CTRL_REG(0x158) 278 + #define PWR_SHADER_PRESENT PWR_CTRL_REG(0x200) 279 + #define PWR_SHADER_READY PWR_CTRL_REG(0x208) 280 + #define PWR_SHADER_PWRTRANS PWR_CTRL_REG(0x210) 281 + #define PWR_SHADER_PWRACTIVE PWR_CTRL_REG(0x218) 282 + #define PWR_BASE_PRESENT PWR_CTRL_REG(0x380) 283 + #define PWR_BASE_READY PWR_CTRL_REG(0x388) 284 + #define PWR_BASE_PWRTRANS PWR_CTRL_REG(0x390) 285 + #define PWR_BASE_PWRACTIVE PWR_CTRL_REG(0x398) 286 + #define PWR_STACK_PRESENT PWR_CTRL_REG(0x3c0) 287 + #define PWR_STACK_READY PWR_CTRL_REG(0x3c8) 288 + #define PWR_STACK_PWRTRANS PWR_CTRL_REG(0x3d0) 289 + 212 290 #endif