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