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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
449 void dpu_hw_intr_destroy(struct dpu_hw_intr *intr)
450 {
451 	kfree(intr);
452 }
453 
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 
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
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 
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 
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 
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