1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 3 */ 4 5 #include <linux/bitops.h> 6 #include <linux/debugfs.h> 7 #include <linux/slab.h> 8 9 #include "dpu_core_irq.h" 10 #include "dpu_kms.h" 11 #include "dpu_hw_interrupts.h" 12 #include "dpu_hw_util.h" 13 #include "dpu_hw_mdss.h" 14 #include "dpu_trace.h" 15 16 /* 17 * Register offsets in MDSS register file for the interrupt registers 18 * w.r.t. the MDP base 19 */ 20 #define MDP_SSPP_TOP0_OFF 0x0 21 #define MDP_INTF_0_OFF 0x6A000 22 #define MDP_INTF_1_OFF 0x6A800 23 #define MDP_INTF_2_OFF 0x6B000 24 #define MDP_INTF_3_OFF 0x6B800 25 #define MDP_INTF_4_OFF 0x6C000 26 #define MDP_INTF_5_OFF 0x6C800 27 #define INTF_INTR_EN 0x1c0 28 #define INTF_INTR_STATUS 0x1c4 29 #define INTF_INTR_CLEAR 0x1c8 30 #define MDP_AD4_0_OFF 0x7C000 31 #define MDP_AD4_1_OFF 0x7D000 32 #define MDP_AD4_INTR_EN_OFF 0x41c 33 #define MDP_AD4_INTR_CLEAR_OFF 0x424 34 #define MDP_AD4_INTR_STATUS_OFF 0x420 35 #define MDP_INTF_0_OFF_REV_7xxx 0x34000 36 #define MDP_INTF_1_OFF_REV_7xxx 0x35000 37 #define MDP_INTF_2_OFF_REV_7xxx 0x36000 38 #define MDP_INTF_3_OFF_REV_7xxx 0x37000 39 #define MDP_INTF_4_OFF_REV_7xxx 0x38000 40 #define MDP_INTF_5_OFF_REV_7xxx 0x39000 41 #define MDP_INTF_6_OFF_REV_7xxx 0x3a000 42 #define MDP_INTF_7_OFF_REV_7xxx 0x3b000 43 #define MDP_INTF_8_OFF_REV_7xxx 0x3c000 44 45 /** 46 * struct dpu_intr_reg - array of DPU register sets 47 * @clr_off: offset to CLEAR reg 48 * @en_off: offset to ENABLE reg 49 * @status_off: offset to STATUS reg 50 */ 51 struct dpu_intr_reg { 52 u32 clr_off; 53 u32 en_off; 54 u32 status_off; 55 }; 56 57 /* 58 * struct dpu_intr_reg - List of DPU interrupt registers 59 * 60 * When making changes be sure to sync with dpu_hw_intr_reg 61 */ 62 static const struct dpu_intr_reg dpu_intr_set[] = { 63 [MDP_SSPP_TOP0_INTR] = { 64 MDP_SSPP_TOP0_OFF+INTR_CLEAR, 65 MDP_SSPP_TOP0_OFF+INTR_EN, 66 MDP_SSPP_TOP0_OFF+INTR_STATUS 67 }, 68 [MDP_SSPP_TOP0_INTR2] = { 69 MDP_SSPP_TOP0_OFF+INTR2_CLEAR, 70 MDP_SSPP_TOP0_OFF+INTR2_EN, 71 MDP_SSPP_TOP0_OFF+INTR2_STATUS 72 }, 73 [MDP_SSPP_TOP0_HIST_INTR] = { 74 MDP_SSPP_TOP0_OFF+HIST_INTR_CLEAR, 75 MDP_SSPP_TOP0_OFF+HIST_INTR_EN, 76 MDP_SSPP_TOP0_OFF+HIST_INTR_STATUS 77 }, 78 [MDP_INTF0_INTR] = { 79 MDP_INTF_0_OFF+INTF_INTR_CLEAR, 80 MDP_INTF_0_OFF+INTF_INTR_EN, 81 MDP_INTF_0_OFF+INTF_INTR_STATUS 82 }, 83 [MDP_INTF1_INTR] = { 84 MDP_INTF_1_OFF+INTF_INTR_CLEAR, 85 MDP_INTF_1_OFF+INTF_INTR_EN, 86 MDP_INTF_1_OFF+INTF_INTR_STATUS 87 }, 88 [MDP_INTF2_INTR] = { 89 MDP_INTF_2_OFF+INTF_INTR_CLEAR, 90 MDP_INTF_2_OFF+INTF_INTR_EN, 91 MDP_INTF_2_OFF+INTF_INTR_STATUS 92 }, 93 [MDP_INTF3_INTR] = { 94 MDP_INTF_3_OFF+INTF_INTR_CLEAR, 95 MDP_INTF_3_OFF+INTF_INTR_EN, 96 MDP_INTF_3_OFF+INTF_INTR_STATUS 97 }, 98 [MDP_INTF4_INTR] = { 99 MDP_INTF_4_OFF+INTF_INTR_CLEAR, 100 MDP_INTF_4_OFF+INTF_INTR_EN, 101 MDP_INTF_4_OFF+INTF_INTR_STATUS 102 }, 103 [MDP_INTF5_INTR] = { 104 MDP_INTF_5_OFF+INTF_INTR_CLEAR, 105 MDP_INTF_5_OFF+INTF_INTR_EN, 106 MDP_INTF_5_OFF+INTF_INTR_STATUS 107 }, 108 [MDP_AD4_0_INTR] = { 109 MDP_AD4_0_OFF + MDP_AD4_INTR_CLEAR_OFF, 110 MDP_AD4_0_OFF + MDP_AD4_INTR_EN_OFF, 111 MDP_AD4_0_OFF + MDP_AD4_INTR_STATUS_OFF, 112 }, 113 [MDP_AD4_1_INTR] = { 114 MDP_AD4_1_OFF + MDP_AD4_INTR_CLEAR_OFF, 115 MDP_AD4_1_OFF + MDP_AD4_INTR_EN_OFF, 116 MDP_AD4_1_OFF + MDP_AD4_INTR_STATUS_OFF, 117 }, 118 [MDP_INTF0_7xxx_INTR] = { 119 MDP_INTF_0_OFF_REV_7xxx+INTF_INTR_CLEAR, 120 MDP_INTF_0_OFF_REV_7xxx+INTF_INTR_EN, 121 MDP_INTF_0_OFF_REV_7xxx+INTF_INTR_STATUS 122 }, 123 [MDP_INTF1_7xxx_INTR] = { 124 MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_CLEAR, 125 MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_EN, 126 MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_STATUS 127 }, 128 [MDP_INTF2_7xxx_INTR] = { 129 MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_CLEAR, 130 MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_EN, 131 MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_STATUS 132 }, 133 [MDP_INTF3_7xxx_INTR] = { 134 MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_CLEAR, 135 MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_EN, 136 MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_STATUS 137 }, 138 [MDP_INTF4_7xxx_INTR] = { 139 MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_CLEAR, 140 MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_EN, 141 MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_STATUS 142 }, 143 [MDP_INTF5_7xxx_INTR] = { 144 MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_CLEAR, 145 MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_EN, 146 MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_STATUS 147 }, 148 [MDP_INTF6_7xxx_INTR] = { 149 MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_CLEAR, 150 MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_EN, 151 MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_STATUS 152 }, 153 [MDP_INTF7_7xxx_INTR] = { 154 MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_CLEAR, 155 MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_EN, 156 MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_STATUS 157 }, 158 [MDP_INTF8_7xxx_INTR] = { 159 MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_CLEAR, 160 MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_EN, 161 MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_STATUS 162 }, 163 }; 164 165 #define DPU_IRQ_REG(irq_idx) (irq_idx / 32) 166 #define DPU_IRQ_MASK(irq_idx) (BIT(irq_idx % 32)) 167 168 /** 169 * dpu_core_irq_callback_handler - dispatch core interrupts 170 * @dpu_kms: Pointer to DPU's KMS structure 171 * @irq_idx: interrupt index 172 */ 173 static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, int irq_idx) 174 { 175 VERB("irq_idx=%d\n", irq_idx); 176 177 if (!dpu_kms->hw_intr->irq_tbl[irq_idx].cb) 178 DRM_ERROR("no registered cb, idx:%d\n", irq_idx); 179 180 atomic_inc(&dpu_kms->hw_intr->irq_tbl[irq_idx].count); 181 182 /* 183 * Perform registered function callback 184 */ 185 dpu_kms->hw_intr->irq_tbl[irq_idx].cb(dpu_kms->hw_intr->irq_tbl[irq_idx].arg, irq_idx); 186 } 187 188 irqreturn_t dpu_core_irq(struct msm_kms *kms) 189 { 190 struct dpu_kms *dpu_kms = to_dpu_kms(kms); 191 struct dpu_hw_intr *intr = dpu_kms->hw_intr; 192 int reg_idx; 193 int irq_idx; 194 u32 irq_status; 195 u32 enable_mask; 196 int bit; 197 unsigned long irq_flags; 198 199 if (!intr) 200 return IRQ_NONE; 201 202 spin_lock_irqsave(&intr->irq_lock, irq_flags); 203 for (reg_idx = 0; reg_idx < ARRAY_SIZE(dpu_intr_set); reg_idx++) { 204 if (!test_bit(reg_idx, &intr->irq_mask)) 205 continue; 206 207 /* Read interrupt status */ 208 irq_status = DPU_REG_READ(&intr->hw, dpu_intr_set[reg_idx].status_off); 209 210 /* Read enable mask */ 211 enable_mask = DPU_REG_READ(&intr->hw, dpu_intr_set[reg_idx].en_off); 212 213 /* and clear the interrupt */ 214 if (irq_status) 215 DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off, 216 irq_status); 217 218 /* Finally update IRQ status based on enable mask */ 219 irq_status &= enable_mask; 220 221 if (!irq_status) 222 continue; 223 224 /* 225 * Search through matching intr status. 226 */ 227 while ((bit = ffs(irq_status)) != 0) { 228 irq_idx = DPU_IRQ_IDX(reg_idx, bit - 1); 229 230 dpu_core_irq_callback_handler(dpu_kms, irq_idx); 231 232 /* 233 * When callback finish, clear the irq_status 234 * with the matching mask. Once irq_status 235 * is all cleared, the search can be stopped. 236 */ 237 irq_status &= ~BIT(bit - 1); 238 } 239 } 240 241 /* ensure register writes go through */ 242 wmb(); 243 244 spin_unlock_irqrestore(&intr->irq_lock, irq_flags); 245 246 return IRQ_HANDLED; 247 } 248 249 static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) 250 { 251 int reg_idx; 252 const struct dpu_intr_reg *reg; 253 const char *dbgstr = NULL; 254 uint32_t cache_irq_mask; 255 256 if (!intr) 257 return -EINVAL; 258 259 if (irq_idx < 0 || irq_idx >= intr->total_irqs) { 260 pr_err("invalid IRQ index: [%d]\n", irq_idx); 261 return -EINVAL; 262 } 263 264 /* 265 * The cache_irq_mask and hardware RMW operations needs to be done 266 * under irq_lock and it's the caller's responsibility to ensure that's 267 * held. 268 */ 269 assert_spin_locked(&intr->irq_lock); 270 271 reg_idx = DPU_IRQ_REG(irq_idx); 272 reg = &dpu_intr_set[reg_idx]; 273 274 cache_irq_mask = intr->cache_irq_mask[reg_idx]; 275 if (cache_irq_mask & DPU_IRQ_MASK(irq_idx)) { 276 dbgstr = "already "; 277 } else { 278 dbgstr = ""; 279 280 cache_irq_mask |= DPU_IRQ_MASK(irq_idx); 281 /* Cleaning any pending interrupt */ 282 DPU_REG_WRITE(&intr->hw, reg->clr_off, DPU_IRQ_MASK(irq_idx)); 283 /* Enabling interrupts with the new mask */ 284 DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); 285 286 /* ensure register write goes through */ 287 wmb(); 288 289 intr->cache_irq_mask[reg_idx] = cache_irq_mask; 290 } 291 292 pr_debug("DPU IRQ %d %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, 293 DPU_IRQ_MASK(irq_idx), cache_irq_mask); 294 295 return 0; 296 } 297 298 static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx) 299 { 300 int reg_idx; 301 const struct dpu_intr_reg *reg; 302 const char *dbgstr = NULL; 303 uint32_t cache_irq_mask; 304 305 if (!intr) 306 return -EINVAL; 307 308 if (irq_idx < 0 || irq_idx >= intr->total_irqs) { 309 pr_err("invalid IRQ index: [%d]\n", irq_idx); 310 return -EINVAL; 311 } 312 313 /* 314 * The cache_irq_mask and hardware RMW operations needs to be done 315 * under irq_lock and it's the caller's responsibility to ensure that's 316 * held. 317 */ 318 assert_spin_locked(&intr->irq_lock); 319 320 reg_idx = DPU_IRQ_REG(irq_idx); 321 reg = &dpu_intr_set[reg_idx]; 322 323 cache_irq_mask = intr->cache_irq_mask[reg_idx]; 324 if ((cache_irq_mask & DPU_IRQ_MASK(irq_idx)) == 0) { 325 dbgstr = "already "; 326 } else { 327 dbgstr = ""; 328 329 cache_irq_mask &= ~DPU_IRQ_MASK(irq_idx); 330 /* Disable interrupts based on the new mask */ 331 DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); 332 /* Cleaning any pending interrupt */ 333 DPU_REG_WRITE(&intr->hw, reg->clr_off, DPU_IRQ_MASK(irq_idx)); 334 335 /* ensure register write goes through */ 336 wmb(); 337 338 intr->cache_irq_mask[reg_idx] = cache_irq_mask; 339 } 340 341 pr_debug("DPU IRQ %d %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr, 342 DPU_IRQ_MASK(irq_idx), cache_irq_mask); 343 344 return 0; 345 } 346 347 static void dpu_clear_irqs(struct dpu_kms *dpu_kms) 348 { 349 struct dpu_hw_intr *intr = dpu_kms->hw_intr; 350 int i; 351 352 if (!intr) 353 return; 354 355 for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { 356 if (test_bit(i, &intr->irq_mask)) 357 DPU_REG_WRITE(&intr->hw, 358 dpu_intr_set[i].clr_off, 0xffffffff); 359 } 360 361 /* ensure register writes go through */ 362 wmb(); 363 } 364 365 static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms) 366 { 367 struct dpu_hw_intr *intr = dpu_kms->hw_intr; 368 int i; 369 370 if (!intr) 371 return; 372 373 for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { 374 if (test_bit(i, &intr->irq_mask)) 375 DPU_REG_WRITE(&intr->hw, 376 dpu_intr_set[i].en_off, 0x00000000); 377 } 378 379 /* ensure register writes go through */ 380 wmb(); 381 } 382 383 u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx) 384 { 385 struct dpu_hw_intr *intr = dpu_kms->hw_intr; 386 int reg_idx; 387 unsigned long irq_flags; 388 u32 intr_status; 389 390 if (!intr) 391 return 0; 392 393 if (irq_idx < 0) { 394 DPU_ERROR("[%pS] invalid irq_idx=%d\n", 395 __builtin_return_address(0), irq_idx); 396 return 0; 397 } 398 399 if (irq_idx < 0 || irq_idx >= intr->total_irqs) { 400 pr_err("invalid IRQ index: [%d]\n", irq_idx); 401 return 0; 402 } 403 404 spin_lock_irqsave(&intr->irq_lock, irq_flags); 405 406 reg_idx = DPU_IRQ_REG(irq_idx); 407 intr_status = DPU_REG_READ(&intr->hw, 408 dpu_intr_set[reg_idx].status_off) & 409 DPU_IRQ_MASK(irq_idx); 410 if (intr_status) 411 DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off, 412 intr_status); 413 414 /* ensure register writes go through */ 415 wmb(); 416 417 spin_unlock_irqrestore(&intr->irq_lock, irq_flags); 418 419 return intr_status; 420 } 421 422 static void __intr_offset(const struct dpu_mdss_cfg *m, 423 void __iomem *addr, struct dpu_hw_blk_reg_map *hw) 424 { 425 hw->blk_addr = addr + m->mdp[0].base; 426 } 427 428 struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, 429 const struct dpu_mdss_cfg *m) 430 { 431 struct dpu_hw_intr *intr; 432 int nirq = MDP_INTR_MAX * 32; 433 434 if (!addr || !m) 435 return ERR_PTR(-EINVAL); 436 437 intr = kzalloc(struct_size(intr, irq_tbl, nirq), GFP_KERNEL); 438 if (!intr) 439 return ERR_PTR(-ENOMEM); 440 441 __intr_offset(m, addr, &intr->hw); 442 443 intr->total_irqs = nirq; 444 445 intr->irq_mask = m->mdss_irqs; 446 447 spin_lock_init(&intr->irq_lock); 448 449 return intr; 450 } 451 452 void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) 453 { 454 kfree(intr); 455 } 456 457 int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, 458 void (*irq_cb)(void *arg, int irq_idx), 459 void *irq_arg) 460 { 461 unsigned long irq_flags; 462 int ret; 463 464 if (!irq_cb) { 465 DPU_ERROR("invalid ird_idx:%d irq_cb:%ps\n", irq_idx, irq_cb); 466 return -EINVAL; 467 } 468 469 if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { 470 DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); 471 return -EINVAL; 472 } 473 474 VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); 475 476 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); 477 478 if (unlikely(WARN_ON(dpu_kms->hw_intr->irq_tbl[irq_idx].cb))) { 479 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); 480 481 return -EBUSY; 482 } 483 484 trace_dpu_core_irq_register_callback(irq_idx, irq_cb); 485 dpu_kms->hw_intr->irq_tbl[irq_idx].arg = irq_arg; 486 dpu_kms->hw_intr->irq_tbl[irq_idx].cb = irq_cb; 487 488 ret = dpu_hw_intr_enable_irq_locked( 489 dpu_kms->hw_intr, 490 irq_idx); 491 if (ret) 492 DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n", 493 irq_idx); 494 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); 495 496 trace_dpu_irq_register_success(irq_idx); 497 498 return 0; 499 } 500 501 int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx) 502 { 503 unsigned long irq_flags; 504 int ret; 505 506 if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->total_irqs) { 507 DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); 508 return -EINVAL; 509 } 510 511 VERB("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); 512 513 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); 514 trace_dpu_core_irq_unregister_callback(irq_idx); 515 516 ret = dpu_hw_intr_disable_irq_locked(dpu_kms->hw_intr, irq_idx); 517 if (ret) 518 DPU_ERROR("Fail to disable IRQ for irq_idx:%d: %d\n", 519 irq_idx, ret); 520 521 dpu_kms->hw_intr->irq_tbl[irq_idx].cb = NULL; 522 dpu_kms->hw_intr->irq_tbl[irq_idx].arg = NULL; 523 524 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); 525 526 trace_dpu_irq_unregister_success(irq_idx); 527 528 return 0; 529 } 530 531 #ifdef CONFIG_DEBUG_FS 532 static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) 533 { 534 struct dpu_kms *dpu_kms = s->private; 535 unsigned long irq_flags; 536 int i, irq_count; 537 void *cb; 538 539 for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) { 540 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags); 541 irq_count = atomic_read(&dpu_kms->hw_intr->irq_tbl[i].count); 542 cb = dpu_kms->hw_intr->irq_tbl[i].cb; 543 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags); 544 545 if (irq_count || cb) 546 seq_printf(s, "idx:%d irq:%d cb:%ps\n", i, irq_count, cb); 547 } 548 549 return 0; 550 } 551 552 DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq); 553 554 void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, 555 struct dentry *parent) 556 { 557 debugfs_create_file("core_irq", 0600, parent, dpu_kms, 558 &dpu_debugfs_core_irq_fops); 559 } 560 #endif 561 562 void dpu_core_irq_preinstall(struct msm_kms *kms) 563 { 564 struct dpu_kms *dpu_kms = to_dpu_kms(kms); 565 int i; 566 567 pm_runtime_get_sync(&dpu_kms->pdev->dev); 568 dpu_clear_irqs(dpu_kms); 569 dpu_disable_all_irqs(dpu_kms); 570 pm_runtime_put_sync(&dpu_kms->pdev->dev); 571 572 for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) 573 atomic_set(&dpu_kms->hw_intr->irq_tbl[i].count, 0); 574 } 575 576 void dpu_core_irq_uninstall(struct msm_kms *kms) 577 { 578 struct dpu_kms *dpu_kms = to_dpu_kms(kms); 579 int i; 580 581 if (!dpu_kms->hw_intr) 582 return; 583 584 pm_runtime_get_sync(&dpu_kms->pdev->dev); 585 for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) 586 if (dpu_kms->hw_intr->irq_tbl[i].cb) 587 DPU_ERROR("irq_idx=%d still enabled/registered\n", i); 588 589 dpu_clear_irqs(dpu_kms); 590 dpu_disable_all_irqs(dpu_kms); 591 pm_runtime_put_sync(&dpu_kms->pdev->dev); 592 } 593