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

drm/imagination: Use callbacks for fw irq handling

This allows for more versatility in checking and clearing firmware
registers used for interrupt handling.

Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Link: https://lore.kernel.org/r/20250410-sets-bxs-4-64-patch-v1-v6-12-eda620c5865f@imgtec.com
Signed-off-by: Matt Coster <matt.coster@imgtec.com>

+63 -44
+18
drivers/gpu/drm/imagination/pvr_device.h
··· 739 739 __union_size, __member_size); \ 740 740 }) 741 741 742 + /* 743 + * These utility functions should more properly be placed in pvr_fw.h, but that 744 + * would cause a dependency cycle between that header and this one. Since 745 + * they're primarily used in pvr_device.c, let's put them in here for now. 746 + */ 747 + 748 + static __always_inline bool 749 + pvr_fw_irq_pending(struct pvr_device *pvr_dev) 750 + { 751 + return pvr_dev->fw_dev.defs->irq_pending(pvr_dev); 752 + } 753 + 754 + static __always_inline void 755 + pvr_fw_irq_clear(struct pvr_device *pvr_dev) 756 + { 757 + pvr_dev->fw_dev.defs->irq_clear(pvr_dev); 758 + } 759 + 742 760 #endif /* PVR_DEVICE_H */
+13 -32
drivers/gpu/drm/imagination/pvr_fw.h
··· 167 167 int (*wrapper_init)(struct pvr_device *pvr_dev); 168 168 169 169 /** 170 - * @irq: FW Interrupt information. 170 + * @irq_pending: Check interrupt status register for pending interrupts. 171 171 * 172 - * Those are processor dependent, and should be initialized by the 173 - * processor backend in pvr_fw_funcs::init(). 172 + * @pvr_dev: Target PowerVR device. 173 + * 174 + * This function is mandatory. 174 175 */ 175 - struct { 176 - /** @status_reg: FW interrupt status register. */ 177 - u32 status_reg; 176 + bool (*irq_pending)(struct pvr_device *pvr_dev); 178 177 179 - /** 180 - * @clear_reg: FW interrupt clear register. 181 - * 182 - * If @status_reg == @clear_reg, we clear by write a bit to zero, 183 - * otherwise we clear by writing a bit to one. 184 - */ 185 - u32 clear_reg; 186 - 187 - /** @status_mask: Bitmask of events to listen for in the status_reg. */ 188 - u32 status_mask; 189 - 190 - /** @clear_mask: Value to write to the clear_reg in order to clear FW IRQs. */ 191 - u32 clear_mask; 192 - } irq; 178 + /** 179 + * @irq_clear: Clear pending interrupts. 180 + * 181 + * @pvr_dev: Target PowerVR device. 182 + * 183 + * This function is mandatory. 184 + */ 185 + void (*irq_clear)(struct pvr_device *pvr_dev); 193 186 194 187 /** 195 188 * @has_fixed_data_addr: Specify whether the firmware fixed data must be loaded at the ··· 382 389 struct mutex lock; 383 390 } fw_objs; 384 391 }; 385 - 386 - #define pvr_fw_irq_read_reg(pvr_dev, name) \ 387 - pvr_cr_read32((pvr_dev), (pvr_dev)->fw_dev.defs->irq.name ## _reg) 388 - 389 - #define pvr_fw_irq_write_reg(pvr_dev, name, value) \ 390 - pvr_cr_write32((pvr_dev), (pvr_dev)->fw_dev.defs->irq.name ## _reg, value) 391 - 392 - #define pvr_fw_irq_pending(pvr_dev) \ 393 - (pvr_fw_irq_read_reg(pvr_dev, status) & (pvr_dev)->fw_dev.defs->irq.status_mask) 394 - 395 - #define pvr_fw_irq_clear(pvr_dev) \ 396 - pvr_fw_irq_write_reg(pvr_dev, clear, (pvr_dev)->fw_dev.defs->irq.clear_mask) 397 392 398 393 enum pvr_fw_processor_type { 399 394 PVR_FW_PROCESSOR_TYPE_META = 0,
+16 -6
drivers/gpu/drm/imagination/pvr_fw_meta.c
··· 532 532 fw_obj->fw_mm_node.start, fw_obj->fw_mm_node.size); 533 533 } 534 534 535 + static bool 536 + pvr_meta_irq_pending(struct pvr_device *pvr_dev) 537 + { 538 + return pvr_cr_read32(pvr_dev, ROGUE_CR_META_SP_MSLVIRQSTATUS) & 539 + ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_EN; 540 + } 541 + 542 + static void 543 + pvr_meta_irq_clear(struct pvr_device *pvr_dev) 544 + { 545 + pvr_cr_write32(pvr_dev, ROGUE_CR_META_SP_MSLVIRQSTATUS, 546 + ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_CLRMSK); 547 + } 548 + 535 549 const struct pvr_fw_defs pvr_fw_defs_meta = { 536 550 .init = pvr_meta_init, 537 551 .fw_process = pvr_meta_fw_process, ··· 553 539 .vm_unmap = pvr_meta_vm_unmap, 554 540 .get_fw_addr_with_offset = pvr_meta_get_fw_addr_with_offset, 555 541 .wrapper_init = pvr_meta_wrapper_init, 556 - .irq = { 557 - .status_reg = ROGUE_CR_META_SP_MSLVIRQSTATUS, 558 - .clear_reg = ROGUE_CR_META_SP_MSLVIRQSTATUS, 559 - .status_mask = ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_EN, 560 - .clear_mask = ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_CLRMSK, 561 - }, 542 + .irq_pending = pvr_meta_irq_pending, 543 + .irq_clear = pvr_meta_irq_clear, 562 544 .has_fixed_data_addr = false, 563 545 };
+16 -6
drivers/gpu/drm/imagination/pvr_fw_mips.c
··· 225 225 ROGUE_FW_HEAP_MIPS_BASE; 226 226 } 227 227 228 + static bool 229 + pvr_mips_irq_pending(struct pvr_device *pvr_dev) 230 + { 231 + return pvr_cr_read32(pvr_dev, ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS) & 232 + ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_EN; 233 + } 234 + 235 + static void 236 + pvr_mips_irq_clear(struct pvr_device *pvr_dev) 237 + { 238 + pvr_cr_write32(pvr_dev, ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR, 239 + ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_EN); 240 + } 241 + 228 242 const struct pvr_fw_defs pvr_fw_defs_mips = { 229 243 .init = pvr_mips_init, 230 244 .fini = pvr_mips_fini, ··· 247 233 .vm_unmap = pvr_vm_mips_unmap, 248 234 .get_fw_addr_with_offset = pvr_mips_get_fw_addr_with_offset, 249 235 .wrapper_init = pvr_mips_wrapper_init, 250 - .irq = { 251 - .status_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS, 252 - .clear_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR, 253 - .status_mask = ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_EN, 254 - .clear_mask = ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_EN, 255 - }, 236 + .irq_pending = pvr_mips_irq_pending, 237 + .irq_clear = pvr_mips_irq_clear, 256 238 .has_fixed_data_addr = true, 257 239 };