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