Loading...
Note: File does not exist in v3.1.
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 <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 registers
20 * w.r.t. the MDP base
21 */
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 sets
45 * @clr_off: offset to CLEAR reg
46 * @en_off: offset to ENABLE reg
47 * @status_off: offset to STATUS reg
48 */
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.x
57 */
58static const struct dpu_intr_reg dpu_intr_set_legacy[] = {
59 [MDP_SSPP_TOP0_INTR] = {
60 INTR_CLEAR,
61 INTR_EN,
62 INTR_STATUS
63 },
64 [MDP_SSPP_TOP0_INTR2] = {
65 INTR2_CLEAR,
66 INTR2_EN,
67 INTR2_STATUS
68 },
69 [MDP_SSPP_TOP0_HIST_INTR] = {
70 HIST_INTR_CLEAR,
71 HIST_INTR_EN,
72 HIST_INTR_STATUS
73 },
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.0
128 */
129static const struct dpu_intr_reg dpu_intr_set_7xxx[] = {
130 [MDP_SSPP_TOP0_INTR] = {
131 INTR_CLEAR,
132 INTR_EN,
133 INTR_STATUS
134 },
135 [MDP_SSPP_TOP0_INTR2] = {
136 INTR2_CLEAR,
137 INTR2_EN,
138 INTR2_STATUS
139 },
140 [MDP_SSPP_TOP0_HIST_INTR] = {
141 HIST_INTR_CLEAR,
142 HIST_INTR_EN,
143 HIST_INTR_STATUS
144 },
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 interrupts
217 * @dpu_kms: Pointer to DPU's KMS structure
218 * @irq_idx: interrupt index
219 */
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
230 atomic_inc(&irq_entry->count);
231
232 /*
233 * Perform registered function callback
234 */
235 irq_entry->cb(irq_entry->arg);
236}
237
238irqreturn_t dpu_core_irq(struct msm_kms *kms)
239{
240 struct dpu_kms *dpu_kms = to_dpu_kms(kms);
241 struct dpu_hw_intr *intr = dpu_kms->hw_intr;
242 int reg_idx;
243 unsigned int irq_idx;
244 u32 irq_status;
245 u32 enable_mask;
246 int bit;
247 unsigned long irq_flags;
248
249 if (!intr)
250 return IRQ_NONE;
251
252 spin_lock_irqsave(&intr->irq_lock, irq_flags);
253 for (reg_idx = 0; reg_idx < MDP_INTR_MAX; reg_idx++) {
254 if (!test_bit(reg_idx, &intr->irq_mask))
255 continue;
256
257 /* Read interrupt status */
258 irq_status = DPU_REG_READ(&intr->hw, intr->intr_set[reg_idx].status_off);
259
260 /* Read enable mask */
261 enable_mask = DPU_REG_READ(&intr->hw, intr->intr_set[reg_idx].en_off);
262
263 /* and clear the interrupt */
264 if (irq_status)
265 DPU_REG_WRITE(&intr->hw, intr->intr_set[reg_idx].clr_off,
266 irq_status);
267
268 /* Finally update IRQ status based on enable mask */
269 irq_status &= enable_mask;
270
271 if (!irq_status)
272 continue;
273
274 /*
275 * Search through matching intr status.
276 */
277 while ((bit = ffs(irq_status)) != 0) {
278 irq_idx = DPU_IRQ_IDX(reg_idx, bit - 1);
279
280 dpu_core_irq_callback_handler(dpu_kms, irq_idx);
281
282 /*
283 * When callback finish, clear the irq_status
284 * with the matching mask. Once irq_status
285 * is all cleared, the search can be stopped.
286 */
287 irq_status &= ~BIT(bit - 1);
288 }
289 }
290
291 /* ensure register writes go through */
292 wmb();
293
294 spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
295
296 return IRQ_HANDLED;
297}
298
299static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr,
300 unsigned int irq_idx)
301{
302 int reg_idx;
303 const struct dpu_intr_reg *reg;
304 const char *dbgstr = NULL;
305 uint32_t cache_irq_mask;
306
307 if (!intr)
308 return -EINVAL;
309
310 if (!dpu_core_irq_is_valid(irq_idx)) {
311 pr_err("invalid IRQ=[%d, %d]\n",
312 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
313 return -EINVAL;
314 }
315
316 /*
317 * The cache_irq_mask and hardware RMW operations needs to be done
318 * under irq_lock and it's the caller's responsibility to ensure that's
319 * held.
320 */
321 assert_spin_locked(&intr->irq_lock);
322
323 reg_idx = DPU_IRQ_REG(irq_idx);
324 reg = &intr->intr_set[reg_idx];
325
326 /* Is this interrupt register supported on the platform */
327 if (WARN_ON(!reg->en_off))
328 return -EINVAL;
329
330 cache_irq_mask = intr->cache_irq_mask[reg_idx];
331 if (cache_irq_mask & DPU_IRQ_MASK(irq_idx)) {
332 dbgstr = "already ";
333 } else {
334 dbgstr = "";
335
336 cache_irq_mask |= DPU_IRQ_MASK(irq_idx);
337 /* Cleaning any pending interrupt */
338 DPU_REG_WRITE(&intr->hw, reg->clr_off, DPU_IRQ_MASK(irq_idx));
339 /* Enabling interrupts with the new mask */
340 DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask);
341
342 /* ensure register write goes through */
343 wmb();
344
345 intr->cache_irq_mask[reg_idx] = cache_irq_mask;
346 }
347
348 pr_debug("DPU IRQ=[%d, %d] %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n",
349 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr,
350 DPU_IRQ_MASK(irq_idx), cache_irq_mask);
351
352 return 0;
353}
354
355static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr,
356 unsigned int irq_idx)
357{
358 int reg_idx;
359 const struct dpu_intr_reg *reg;
360 const char *dbgstr = NULL;
361 uint32_t cache_irq_mask;
362
363 if (!intr)
364 return -EINVAL;
365
366 if (!dpu_core_irq_is_valid(irq_idx)) {
367 pr_err("invalid IRQ=[%d, %d]\n",
368 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
369 return -EINVAL;
370 }
371
372 /*
373 * The cache_irq_mask and hardware RMW operations needs to be done
374 * under irq_lock and it's the caller's responsibility to ensure that's
375 * held.
376 */
377 assert_spin_locked(&intr->irq_lock);
378
379 reg_idx = DPU_IRQ_REG(irq_idx);
380 reg = &intr->intr_set[reg_idx];
381
382 cache_irq_mask = intr->cache_irq_mask[reg_idx];
383 if ((cache_irq_mask & DPU_IRQ_MASK(irq_idx)) == 0) {
384 dbgstr = "already ";
385 } else {
386 dbgstr = "";
387
388 cache_irq_mask &= ~DPU_IRQ_MASK(irq_idx);
389 /* Disable interrupts based on the new mask */
390 DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask);
391 /* Cleaning any pending interrupt */
392 DPU_REG_WRITE(&intr->hw, reg->clr_off, DPU_IRQ_MASK(irq_idx));
393
394 /* ensure register write goes through */
395 wmb();
396
397 intr->cache_irq_mask[reg_idx] = cache_irq_mask;
398 }
399
400 pr_debug("DPU IRQ=[%d, %d] %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n",
401 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), dbgstr,
402 DPU_IRQ_MASK(irq_idx), cache_irq_mask);
403
404 return 0;
405}
406
407static void dpu_clear_irqs(struct dpu_kms *dpu_kms)
408{
409 struct dpu_hw_intr *intr = dpu_kms->hw_intr;
410 int i;
411
412 if (!intr)
413 return;
414
415 for (i = 0; i < MDP_INTR_MAX; i++) {
416 if (test_bit(i, &intr->irq_mask))
417 DPU_REG_WRITE(&intr->hw,
418 intr->intr_set[i].clr_off, 0xffffffff);
419 }
420
421 /* ensure register writes go through */
422 wmb();
423}
424
425static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms)
426{
427 struct dpu_hw_intr *intr = dpu_kms->hw_intr;
428 int i;
429
430 if (!intr)
431 return;
432
433 for (i = 0; i < MDP_INTR_MAX; i++) {
434 if (test_bit(i, &intr->irq_mask))
435 DPU_REG_WRITE(&intr->hw,
436 intr->intr_set[i].en_off, 0x00000000);
437 }
438
439 /* ensure register writes go through */
440 wmb();
441}
442
443u32 dpu_core_irq_read(struct dpu_kms *dpu_kms,
444 unsigned int irq_idx)
445{
446 struct dpu_hw_intr *intr = dpu_kms->hw_intr;
447 int reg_idx;
448 unsigned long irq_flags;
449 u32 intr_status;
450
451 if (!intr)
452 return 0;
453
454 if (!dpu_core_irq_is_valid(irq_idx)) {
455 pr_err("invalid IRQ=[%d, %d]\n", DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
456 return 0;
457 }
458
459 spin_lock_irqsave(&intr->irq_lock, irq_flags);
460
461 reg_idx = DPU_IRQ_REG(irq_idx);
462 intr_status = DPU_REG_READ(&intr->hw,
463 intr->intr_set[reg_idx].status_off) &
464 DPU_IRQ_MASK(irq_idx);
465 if (intr_status)
466 DPU_REG_WRITE(&intr->hw, intr->intr_set[reg_idx].clr_off,
467 intr_status);
468
469 /* ensure register writes go through */
470 wmb();
471
472 spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
473
474 return intr_status;
475}
476
477struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev,
478 void __iomem *addr,
479 const struct dpu_mdss_cfg *m)
480{
481 struct dpu_hw_intr *intr;
482 unsigned int i;
483
484 if (!addr || !m)
485 return ERR_PTR(-EINVAL);
486
487 intr = drmm_kzalloc(dev, sizeof(*intr), GFP_KERNEL);
488 if (!intr)
489 return ERR_PTR(-ENOMEM);
490
491 if (m->mdss_ver->core_major_ver >= 7)
492 intr->intr_set = dpu_intr_set_7xxx;
493 else
494 intr->intr_set = dpu_intr_set_legacy;
495
496 intr->hw.blk_addr = addr + m->mdp[0].base;
497
498 intr->irq_mask = BIT(MDP_SSPP_TOP0_INTR) |
499 BIT(MDP_SSPP_TOP0_INTR2) |
500 BIT(MDP_SSPP_TOP0_HIST_INTR);
501 for (i = 0; i < m->intf_count; i++) {
502 const struct dpu_intf_cfg *intf = &m->intf[i];
503
504 if (intf->type == INTF_NONE)
505 continue;
506
507 intr->irq_mask |= BIT(MDP_INTFn_INTR(intf->id));
508
509 if (intf->intr_tear_rd_ptr)
510 intr->irq_mask |= BIT(DPU_IRQ_REG(intf->intr_tear_rd_ptr));
511 }
512
513 spin_lock_init(&intr->irq_lock);
514
515 return intr;
516}
517
518int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms,
519 unsigned int irq_idx,
520 void (*irq_cb)(void *arg),
521 void *irq_arg)
522{
523 struct dpu_hw_intr_entry *irq_entry;
524 unsigned long irq_flags;
525 int ret;
526
527 if (!irq_cb) {
528 DPU_ERROR("invalid IRQ=[%d, %d] irq_cb:%ps\n",
529 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb);
530 return -EINVAL;
531 }
532
533 if (!dpu_core_irq_is_valid(irq_idx)) {
534 DPU_ERROR("invalid IRQ=[%d, %d]\n",
535 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
536 return -EINVAL;
537 }
538
539 VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0),
540 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
541
542 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);
543
544 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);
545 if (unlikely(WARN_ON(irq_entry->cb))) {
546 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
547
548 return -EBUSY;
549 }
550
551 trace_dpu_core_irq_register_callback(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), irq_cb);
552 irq_entry->arg = irq_arg;
553 irq_entry->cb = irq_cb;
554
555 ret = dpu_hw_intr_enable_irq_locked(
556 dpu_kms->hw_intr,
557 irq_idx);
558 if (ret)
559 DPU_ERROR("Failed/ to enable IRQ=[%d, %d]\n",
560 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
561 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
562
563 trace_dpu_irq_register_success(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
564
565 return 0;
566}
567
568int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms,
569 unsigned int irq_idx)
570{
571 struct dpu_hw_intr_entry *irq_entry;
572 unsigned long irq_flags;
573 int ret;
574
575 if (!dpu_core_irq_is_valid(irq_idx)) {
576 DPU_ERROR("invalid IRQ=[%d, %d]\n",
577 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
578 return -EINVAL;
579 }
580
581 VERB("[%pS] IRQ=[%d, %d]\n", __builtin_return_address(0),
582 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
583
584 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);
585 trace_dpu_core_irq_unregister_callback(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
586
587 ret = dpu_hw_intr_disable_irq_locked(dpu_kms->hw_intr, irq_idx);
588 if (ret)
589 DPU_ERROR("Failed to disable IRQ=[%d, %d]: %d\n",
590 DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx), ret);
591
592 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, irq_idx);
593 irq_entry->cb = NULL;
594 irq_entry->arg = NULL;
595
596 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
597
598 trace_dpu_irq_unregister_success(DPU_IRQ_REG(irq_idx), DPU_IRQ_BIT(irq_idx));
599
600 return 0;
601}
602
603#ifdef CONFIG_DEBUG_FS
604static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v)
605{
606 struct dpu_kms *dpu_kms = s->private;
607 struct dpu_hw_intr_entry *irq_entry;
608 unsigned long irq_flags;
609 int i, irq_count;
610 void *cb;
611
612 for (i = 1; i <= DPU_NUM_IRQS; i++) {
613 spin_lock_irqsave(&dpu_kms->hw_intr->irq_lock, irq_flags);
614 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);
615 irq_count = atomic_read(&irq_entry->count);
616 cb = irq_entry->cb;
617 spin_unlock_irqrestore(&dpu_kms->hw_intr->irq_lock, irq_flags);
618
619 if (irq_count || cb)
620 seq_printf(s, "IRQ=[%d, %d] count:%d cb:%ps\n",
621 DPU_IRQ_REG(i), DPU_IRQ_BIT(i), irq_count, cb);
622 }
623
624 return 0;
625}
626
627DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq);
628
629void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms,
630 struct dentry *parent)
631{
632 debugfs_create_file("core_irq", 0600, parent, dpu_kms,
633 &dpu_debugfs_core_irq_fops);
634}
635#endif
636
637void dpu_core_irq_preinstall(struct msm_kms *kms)
638{
639 struct dpu_kms *dpu_kms = to_dpu_kms(kms);
640 struct dpu_hw_intr_entry *irq_entry;
641 int i;
642
643 pm_runtime_get_sync(&dpu_kms->pdev->dev);
644 dpu_clear_irqs(dpu_kms);
645 dpu_disable_all_irqs(dpu_kms);
646 pm_runtime_put_sync(&dpu_kms->pdev->dev);
647
648 for (i = 1; i <= DPU_NUM_IRQS; i++) {
649 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);
650 atomic_set(&irq_entry->count, 0);
651 }
652}
653
654void dpu_core_irq_uninstall(struct msm_kms *kms)
655{
656 struct dpu_kms *dpu_kms = to_dpu_kms(kms);
657 struct dpu_hw_intr_entry *irq_entry;
658 int i;
659
660 if (!dpu_kms->hw_intr)
661 return;
662
663 pm_runtime_get_sync(&dpu_kms->pdev->dev);
664 for (i = 1; i <= DPU_NUM_IRQS; i++) {
665 irq_entry = dpu_core_irq_get_entry(dpu_kms->hw_intr, i);
666 if (irq_entry->cb)
667 DPU_ERROR("IRQ=[%d, %d] still enabled/registered\n",
668 DPU_IRQ_REG(i), DPU_IRQ_BIT(i));
669 }
670
671 dpu_clear_irqs(dpu_kms);
672 dpu_disable_all_irqs(dpu_kms);
673 pm_runtime_put_sync(&dpu_kms->pdev->dev);
674}