677 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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 <drm/drm_managed.h>10 11#include "dpu_core_irq.h"12#include "dpu_kms.h"13#include "dpu_hw_interrupts.h"14#include "dpu_hw_util.h"15#include "dpu_hw_mdss.h"16#include "dpu_trace.h"17 18/*19 * Register offsets in MDSS register file for the interrupt registers20 * w.r.t. the MDP base21 */22#define MDP_INTF_OFF(intf) (0x6A000 + 0x800 * (intf))23#define MDP_INTF_INTR_EN(intf) (MDP_INTF_OFF(intf) + 0x1c0)24#define MDP_INTF_INTR_STATUS(intf) (MDP_INTF_OFF(intf) + 0x1c4)25#define MDP_INTF_INTR_CLEAR(intf) (MDP_INTF_OFF(intf) + 0x1c8)26#define MDP_INTF_TEAR_OFF(intf) (0x6D700 + 0x100 * (intf))27#define MDP_INTF_INTR_TEAR_EN(intf) (MDP_INTF_TEAR_OFF(intf) + 0x000)28#define MDP_INTF_INTR_TEAR_STATUS(intf) (MDP_INTF_TEAR_OFF(intf) + 0x004)29#define MDP_INTF_INTR_TEAR_CLEAR(intf) (MDP_INTF_TEAR_OFF(intf) + 0x008)30#define MDP_AD4_OFF(ad4) (0x7C000 + 0x1000 * (ad4))31#define MDP_AD4_INTR_EN_OFF(ad4) (MDP_AD4_OFF(ad4) + 0x41c)32#define MDP_AD4_INTR_CLEAR_OFF(ad4) (MDP_AD4_OFF(ad4) + 0x424)33#define MDP_AD4_INTR_STATUS_OFF(ad4) (MDP_AD4_OFF(ad4) + 0x420)34#define MDP_INTF_REV_7xxx_OFF(intf) (0x34000 + 0x1000 * (intf))35#define MDP_INTF_REV_7xxx_INTR_EN(intf) (MDP_INTF_REV_7xxx_OFF(intf) + 0x1c0)36#define MDP_INTF_REV_7xxx_INTR_STATUS(intf) (MDP_INTF_REV_7xxx_OFF(intf) + 0x1c4)37#define MDP_INTF_REV_7xxx_INTR_CLEAR(intf) (MDP_INTF_REV_7xxx_OFF(intf) + 0x1c8)38#define MDP_INTF_REV_7xxx_TEAR_OFF(intf) (0x34800 + 0x1000 * (intf))39#define MDP_INTF_REV_7xxx_INTR_TEAR_EN(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x000)40#define MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x004)41#define MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x008)42 43/**44 * struct dpu_intr_reg - array of DPU register sets45 * @clr_off: offset to CLEAR reg46 * @en_off: offset to ENABLE reg47 * @status_off: offset to STATUS reg48 */49struct dpu_intr_reg {50 u32 clr_off;51 u32 en_off;52 u32 status_off;53};54 55/*56 * dpu_intr_set_legacy - List of DPU interrupt registers for DPU <= 6.x57 */58static const struct dpu_intr_reg dpu_intr_set_legacy[] = {59 [MDP_SSPP_TOP0_INTR] = {60 INTR_CLEAR,61 INTR_EN,62 INTR_STATUS63 },64 [MDP_SSPP_TOP0_INTR2] = {65 INTR2_CLEAR,66 INTR2_EN,67 INTR2_STATUS68 },69 [MDP_SSPP_TOP0_HIST_INTR] = {70 HIST_INTR_CLEAR,71 HIST_INTR_EN,72 HIST_INTR_STATUS73 },74 [MDP_INTF0_INTR] = {75 MDP_INTF_INTR_CLEAR(0),76 MDP_INTF_INTR_EN(0),77 MDP_INTF_INTR_STATUS(0)78 },79 [MDP_INTF1_INTR] = {80 MDP_INTF_INTR_CLEAR(1),81 MDP_INTF_INTR_EN(1),82 MDP_INTF_INTR_STATUS(1)83 },84 [MDP_INTF2_INTR] = {85 MDP_INTF_INTR_CLEAR(2),86 MDP_INTF_INTR_EN(2),87 MDP_INTF_INTR_STATUS(2)88 },89 [MDP_INTF3_INTR] = {90 MDP_INTF_INTR_CLEAR(3),91 MDP_INTF_INTR_EN(3),92 MDP_INTF_INTR_STATUS(3)93 },94 [MDP_INTF4_INTR] = {95 MDP_INTF_INTR_CLEAR(4),96 MDP_INTF_INTR_EN(4),97 MDP_INTF_INTR_STATUS(4)98 },99 [MDP_INTF5_INTR] = {100 MDP_INTF_INTR_CLEAR(5),101 MDP_INTF_INTR_EN(5),102 MDP_INTF_INTR_STATUS(5)103 },104 [MDP_INTF1_TEAR_INTR] = {105 MDP_INTF_INTR_TEAR_CLEAR(1),106 MDP_INTF_INTR_TEAR_EN(1),107 MDP_INTF_INTR_TEAR_STATUS(1)108 },109 [MDP_INTF2_TEAR_INTR] = {110 MDP_INTF_INTR_TEAR_CLEAR(2),111 MDP_INTF_INTR_TEAR_EN(2),112 MDP_INTF_INTR_TEAR_STATUS(2)113 },114 [MDP_AD4_0_INTR] = {115 MDP_AD4_INTR_CLEAR_OFF(0),116 MDP_AD4_INTR_EN_OFF(0),117 MDP_AD4_INTR_STATUS_OFF(0),118 },119 [MDP_AD4_1_INTR] = {120 MDP_AD4_INTR_CLEAR_OFF(1),121 MDP_AD4_INTR_EN_OFF(1),122 MDP_AD4_INTR_STATUS_OFF(1),123 },124};125 126/*127 * dpu_intr_set_7xxx - List of DPU interrupt registers for DPU >= 7.0128 */129static const struct dpu_intr_reg dpu_intr_set_7xxx[] = {130 [MDP_SSPP_TOP0_INTR] = {131 INTR_CLEAR,132 INTR_EN,133 INTR_STATUS134 },135 [MDP_SSPP_TOP0_INTR2] = {136 INTR2_CLEAR,137 INTR2_EN,138 INTR2_STATUS139 },140 [MDP_SSPP_TOP0_HIST_INTR] = {141 HIST_INTR_CLEAR,142 HIST_INTR_EN,143 HIST_INTR_STATUS144 },145 [MDP_INTF0_INTR] = {146 MDP_INTF_REV_7xxx_INTR_CLEAR(0),147 MDP_INTF_REV_7xxx_INTR_EN(0),148 MDP_INTF_REV_7xxx_INTR_STATUS(0)149 },150 [MDP_INTF1_INTR] = {151 MDP_INTF_REV_7xxx_INTR_CLEAR(1),152 MDP_INTF_REV_7xxx_INTR_EN(1),153 MDP_INTF_REV_7xxx_INTR_STATUS(1)154 },155 [MDP_INTF1_TEAR_INTR] = {156 MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(1),157 MDP_INTF_REV_7xxx_INTR_TEAR_EN(1),158 MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(1)159 },160 [MDP_INTF2_INTR] = {161 MDP_INTF_REV_7xxx_INTR_CLEAR(2),162 MDP_INTF_REV_7xxx_INTR_EN(2),163 MDP_INTF_REV_7xxx_INTR_STATUS(2)164 },165 [MDP_INTF2_TEAR_INTR] = {166 MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(2),167 MDP_INTF_REV_7xxx_INTR_TEAR_EN(2),168 MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(2)169 },170 [MDP_INTF3_INTR] = {171 MDP_INTF_REV_7xxx_INTR_CLEAR(3),172 MDP_INTF_REV_7xxx_INTR_EN(3),173 MDP_INTF_REV_7xxx_INTR_STATUS(3)174 },175 [MDP_INTF4_INTR] = {176 MDP_INTF_REV_7xxx_INTR_CLEAR(4),177 MDP_INTF_REV_7xxx_INTR_EN(4),178 MDP_INTF_REV_7xxx_INTR_STATUS(4)179 },180 [MDP_INTF5_INTR] = {181 MDP_INTF_REV_7xxx_INTR_CLEAR(5),182 MDP_INTF_REV_7xxx_INTR_EN(5),183 MDP_INTF_REV_7xxx_INTR_STATUS(5)184 },185 [MDP_INTF6_INTR] = {186 MDP_INTF_REV_7xxx_INTR_CLEAR(6),187 MDP_INTF_REV_7xxx_INTR_EN(6),188 MDP_INTF_REV_7xxx_INTR_STATUS(6)189 },190 [MDP_INTF7_INTR] = {191 MDP_INTF_REV_7xxx_INTR_CLEAR(7),192 MDP_INTF_REV_7xxx_INTR_EN(7),193 MDP_INTF_REV_7xxx_INTR_STATUS(7)194 },195 [MDP_INTF8_INTR] = {196 MDP_INTF_REV_7xxx_INTR_CLEAR(8),197 MDP_INTF_REV_7xxx_INTR_EN(8),198 MDP_INTF_REV_7xxx_INTR_STATUS(8)199 },200};201 202#define DPU_IRQ_MASK(irq_idx) (BIT(DPU_IRQ_BIT(irq_idx)))203 204static inline bool dpu_core_irq_is_valid(unsigned int irq_idx)205{206 return irq_idx && irq_idx <= DPU_NUM_IRQS;207}208 209static inline struct dpu_hw_intr_entry *dpu_core_irq_get_entry(struct dpu_hw_intr *intr,210 unsigned int irq_idx)211{212 return &intr->irq_tbl[irq_idx - 1];213}214 215/**216 * dpu_core_irq_callback_handler - dispatch core interrupts217 * @dpu_kms: Pointer to DPU's KMS structure218 * @irq_idx: interrupt index219 */220static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, unsigned int irq_idx)221{222 struct dpu_hw_intr_entry *irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);223 224 VERB("IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));225 226 if (!irq_entry->cb) {227 DRM_ERROR("no registered cb, IRQ=[%d, %d]\n",228 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));229 return;230 }231 232 atomic_inc(&irq_entry->count);233 234 /*235 * Perform registered function callback236 */237 irq_entry->cb(irq_entry->arg);238}239 240irqreturn_t dpu_core_irq(struct msm_kms *kms)241{242 struct dpu_kms *dpu_kms = to_dpu_kms(kms);243 struct dpu_hw_intr *intr = dpu_kms->hw_intr;244 int reg_idx;245 unsigned int irq_idx;246 u32 irq_status;247 u32 enable_mask;248 int bit;249 unsigned long irq_flags;250 251 if (!intr)252 return IRQ_NONE;253 254 spin_lock_irqsave(&intr->irq_lock, irq_flags);255 for (reg_idx = 0; reg_idx < MDP_INTR_MAX; reg_idx++) {256 if (!test_bit(reg_idx, &intr->irq_mask))257 continue;258 259 /* Read interrupt status */260 irq_status = DPU_REG_READ(&intr->hw, intr->intr_set[reg_idx].status_off);261 262 /* Read enable mask */263 enable_mask = DPU_REG_READ(&intr->hw, intr->intr_set[reg_idx].en_off);264 265 /* and clear the interrupt */266 if (irq_status)267 DPU_REG_WRITE(&intr->hw, intr->intr_set[reg_idx].clr_off,268 irq_status);269 270 /* Finally update IRQ status based on enable mask */271 irq_status &= enable_mask;272 273 if (!irq_status)274 continue;275 276 /*277 * Search through matching intr status.278 */279 while ((bit = ffs(irq_status)) != 0) {280 irq_idx = DPU_IRQ_IDX(reg_idx, bit - 1);281 282 dpu_core_irq_callback_handler(dpu_kms, irq_idx);283 284 /*285 * When callback finish, clear the irq_status286 * with the matching mask. Once irq_status287 * is all cleared, the search can be stopped.288 */289 irq_status &= ~BIT(bit - 1);290 }291 }292 293 /* ensure register writes go through */294 wmb();295 296 spin_unlock_irqrestore(&intr->irq_lock, irq_flags);297 298 return IRQ_HANDLED;299}300 301static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr,302 unsigned int irq_idx)303{304 int reg_idx;305 const struct dpu_intr_reg *reg;306 const char *dbgstr = NULL;307 uint32_t cache_irq_mask;308 309 if (!intr)310 return -EINVAL;311 312 if (!dpu_core_irq_is_valid(irq_idx)) {313 pr_err("invalid IRQ=[%d, %d]\n",314 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));315 return -EINVAL;316 }317 318 /*319 * The cache_irq_mask and hardware RMW operations needs to be done320 * under irq_lock and it's the caller's responsibility to ensure that's321 * held.322 */323 assert_spin_locked(&intr->irq_lock);324 325 reg_idx = DPU_IRQ_REG(irq_idx);326 reg = &intr->intr_set[reg_idx];327 328 /* Is this interrupt register supported on the platform */329 if (WARN_ON(!reg->en_off))330 return -EINVAL;331 332 cache_irq_mask = intr->cache_irq_mask[reg_idx];333 if (cache_irq_mask & DPU_IRQ_MASK(irq_idx)) {334 dbgstr = "already ";335 } else {336 dbgstr = "";337 338 cache_irq_mask |= DPU_IRQ_MASK(irq_idx);339 /* Cleaning any pending interrupt */340 DPU_REG_WRITE(&intr->hw, reg->clr_off, DPU_IRQ_MASK(irq_idx));341 /* Enabling interrupts with the new mask */342 DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask);343 344 /* ensure register write goes through */345 wmb();346 347 intr->cache_irq_mask[reg_idx] = cache_irq_mask;348 }349 350 pr_debug("DPU IRQ=[%d, %d] %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n",351 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr,352 DPU_IRQ_MASK(irq_idx), cache_irq_mask);353 354 return 0;355}356 357static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr,358 unsigned int irq_idx)359{360 int reg_idx;361 const struct dpu_intr_reg *reg;362 const char *dbgstr = NULL;363 uint32_t cache_irq_mask;364 365 if (!intr)366 return -EINVAL;367 368 if (!dpu_core_irq_is_valid(irq_idx)) {369 pr_err("invalid IRQ=[%d, %d]\n",370 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));371 return -EINVAL;372 }373 374 /*375 * The cache_irq_mask and hardware RMW operations needs to be done376 * under irq_lock and it's the caller's responsibility to ensure that's377 * held.378 */379 assert_spin_locked(&intr->irq_lock);380 381 reg_idx = DPU_IRQ_REG(irq_idx);382 reg = &intr->intr_set[reg_idx];383 384 cache_irq_mask = intr->cache_irq_mask[reg_idx];385 if ((cache_irq_mask & DPU_IRQ_MASK(irq_idx)) == 0) {386 dbgstr = "already ";387 } else {388 dbgstr = "";389 390 cache_irq_mask &= ~DPU_IRQ_MASK(irq_idx);391 /* Disable interrupts based on the new mask */392 DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask);393 /* Cleaning any pending interrupt */394 DPU_REG_WRITE(&intr->hw, reg->clr_off, DPU_IRQ_MASK(irq_idx));395 396 /* ensure register write goes through */397 wmb();398 399 intr->cache_irq_mask[reg_idx] = cache_irq_mask;400 }401 402 pr_debug("DPU IRQ=[%d, %d] %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n",403 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr,404 DPU_IRQ_MASK(irq_idx), cache_irq_mask);405 406 return 0;407}408 409static void dpu_clear_irqs(struct dpu_kms *dpu_kms)410{411 struct dpu_hw_intr *intr = dpu_kms->hw_intr;412 int i;413 414 if (!intr)415 return;416 417 for (i = 0; i < MDP_INTR_MAX; i++) {418 if (test_bit(i, &intr->irq_mask))419 DPU_REG_WRITE(&intr->hw,420 intr->intr_set[i].clr_off, 0xffffffff);421 }422 423 /* ensure register writes go through */424 wmb();425}426 427static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms)428{429 struct dpu_hw_intr *intr = dpu_kms->hw_intr;430 int i;431 432 if (!intr)433 return;434 435 for (i = 0; i < MDP_INTR_MAX; i++) {436 if (test_bit(i, &intr->irq_mask))437 DPU_REG_WRITE(&intr->hw,438 intr->intr_set[i].en_off, 0x00000000);439 }440 441 /* ensure register writes go through */442 wmb();443}444 445u32 dpu_core_irq_read(struct dpu_kms *dpu_kms,446 unsigned int irq_idx)447{448 struct dpu_hw_intr *intr = dpu_kms->hw_intr;449 int reg_idx;450 unsigned long irq_flags;451 u32 intr_status;452 453 if (!intr)454 return 0;455 456 if (!dpu_core_irq_is_valid(irq_idx)) {457 pr_err("invalid IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));458 return 0;459 }460 461 spin_lock_irqsave(&intr->irq_lock, irq_flags);462 463 reg_idx = DPU_IRQ_REG(irq_idx);464 intr_status = DPU_REG_READ(&intr->hw,465 intr->intr_set[reg_idx].status_off) &466 DPU_IRQ_MASK(irq_idx);467 if (intr_status)468 DPU_REG_WRITE(&intr->hw, intr->intr_set[reg_idx].clr_off,469 intr_status);470 471 /* ensure register writes go through */472 wmb();473 474 spin_unlock_irqrestore(&intr->irq_lock, irq_flags);475 476 return intr_status;477}478 479struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev,480 void __iomem *addr,481 const struct dpu_mdss_cfg *m)482{483 struct dpu_hw_intr *intr;484 unsigned int i;485 486 if (!addr || !m)487 return ERR_PTR(-EINVAL);488 489 intr = drmm_kzalloc(dev, sizeof(*intr), GFP_KERNEL);490 if (!intr)491 return ERR_PTR(-ENOMEM);492 493 if (m->mdss_ver->core_major_ver >= 7)494 intr->intr_set = dpu_intr_set_7xxx;495 else496 intr->intr_set = dpu_intr_set_legacy;497 498 intr->hw.blk_addr = addr + m->mdp[0].base;499 500 intr->irq_mask = BIT(MDP_SSPP_TOP0_INTR) |501 BIT(MDP_SSPP_TOP0_INTR2) |502 BIT(MDP_SSPP_TOP0_HIST_INTR);503 for (i = 0; i < m->intf_count; i++) {504 const struct dpu_intf_cfg *intf = &m->intf[i];505 506 if (intf->type == INTF_NONE)507 continue;508 509 intr->irq_mask |= BIT(MDP_INTFn_INTR(intf->id));510 511 if (intf->intr_tear_rd_ptr)512 intr->irq_mask |= BIT(DPU_IRQ_REG(intf->intr_tear_rd_ptr));513 }514 515 spin_lock_init(&intr->irq_lock);516 517 return intr;518}519 520int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms,521 unsigned int irq_idx,522 void (*irq_cb)(void *arg),523 void *irq_arg)524{525 struct dpu_hw_intr_entry *irq_entry;526 unsigned long irq_flags;527 int ret;528 529 if (!irq_cb) {530 DPU_ERROR("IRQ=[%d, %d] NULL callback\n",531 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));532 return -EINVAL;533 }534 535 if (!dpu_core_irq_is_valid(irq_idx)) {536 DPU_ERROR("invalid IRQ=[%d, %d] irq_cb:%ps\n",537 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb);538 return -EINVAL;539 }540 541 VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0),542 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));543 544 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);545 546 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);547 if (unlikely(WARN_ON(irq_entry->cb))) {548 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);549 550 return -EBUSY;551 }552 553 trace_dpu_core_irq_register_callback(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb);554 irq_entry->arg = irq_arg;555 irq_entry->cb = irq_cb;556 557 ret = dpu_hw_intr_enable_irq_locked(558 dpu_kms->hw_intr,559 irq_idx);560 if (ret)561 DPU_ERROR("Failed/ to enable IRQ=[%d, %d]\n",562 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));563 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);564 565 trace_dpu_irq_register_success(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));566 567 return 0;568}569 570int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms,571 unsigned int irq_idx)572{573 struct dpu_hw_intr_entry *irq_entry;574 unsigned long irq_flags;575 int ret;576 577 if (!dpu_core_irq_is_valid(irq_idx)) {578 DPU_ERROR("invalid IRQ=[%d, %d]\n",579 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));580 return -EINVAL;581 }582 583 VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0),584 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));585 586 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);587 trace_dpu_core_irq_unregister_callback(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));588 589 ret = dpu_hw_intr_disable_irq_locked(dpu_kms->hw_intr, irq_idx);590 if (ret)591 DPU_ERROR("Failed to disable IRQ=[%d, %d]: %d\n",592 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), ret);593 594 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);595 irq_entry->cb = NULL;596 irq_entry->arg = NULL;597 598 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);599 600 trace_dpu_irq_unregister_success(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));601 602 return 0;603}604 605#ifdef CONFIG_DEBUG_FS606static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)607{608 struct dpu_kms *dpu_kms = s->private;609 struct dpu_hw_intr_entry *irq_entry;610 unsigned long irq_flags;611 int i, irq_count;612 void *cb;613 614 for (i = 1; i <= DPU_NUM_IRQS; i++) {615 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);616 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);617 irq_count = atomic_read(&irq_entry->count);618 cb = irq_entry->cb;619 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);620 621 if (irq_count || cb)622 seq_printf(s, "IRQ=[%d, %d] count:%d cb:%ps\n",623 DPU_IRQ_REG(i), DPU_IRQ_BIT(i), irq_count, cb);624 }625 626 return 0;627}628 629DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq);630 631void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,632 struct dentry *parent)633{634 debugfs_create_file("core_irq", 0600, parent, dpu_kms,635 &dpu_debugfs_core_irq_fops);636}637#endif638 639void dpu_core_irq_preinstall(struct msm_kms *kms)640{641 struct dpu_kms *dpu_kms = to_dpu_kms(kms);642 struct dpu_hw_intr_entry *irq_entry;643 int i;644 645 pm_runtime_get_sync(&dpu_kms->pdev->dev);646 dpu_clear_irqs(dpu_kms);647 dpu_disable_all_irqs(dpu_kms);648 pm_runtime_put_sync(&dpu_kms->pdev->dev);649 650 for (i = 1; i <= DPU_NUM_IRQS; i++) {651 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);652 atomic_set(&irq_entry->count, 0);653 }654}655 656void dpu_core_irq_uninstall(struct msm_kms *kms)657{658 struct dpu_kms *dpu_kms = to_dpu_kms(kms);659 struct dpu_hw_intr_entry *irq_entry;660 int i;661 662 if (!dpu_kms->hw_intr)663 return;664 665 pm_runtime_get_sync(&dpu_kms->pdev->dev);666 for (i = 1; i <= DPU_NUM_IRQS; i++) {667 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);668 if (irq_entry->cb)669 DPU_ERROR("IRQ=[%d, %d] still enabled/registered\n",670 DPU_IRQ_REG(i), DPU_IRQ_BIT(i));671 }672 673 dpu_clear_irqs(dpu_kms);674 dpu_disable_all_irqs(dpu_kms);675 pm_runtime_put_sync(&dpu_kms->pdev->dev);676}677