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		return;
230	}
231
232	atomic_inc(&irq_entry->count);
233
234	/*
235	 * Perform registered function callback
236	 */
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_status
286			 * with the matching mask. Once irq_status
287			 * 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 done
320	 * under irq_lock and it's the caller's responsibility to ensure that's
321	 * 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 done
376	 * under irq_lock and it's the caller's responsibility to ensure that's
377	 * 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	else
496		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_FS
606static 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#endif
638
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