1 /*
2  * Copyright 2015 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include <drm/drmP.h>
27 
28 #include "dm_services_types.h"
29 #include "dc.h"
30 
31 #include "amdgpu.h"
32 #include "amdgpu_dm.h"
33 #include "amdgpu_dm_irq.h"
34 
35 /******************************************************************************
36  * Private declarations.
37  *****************************************************************************/
38 
39 struct handler_common_data {
40 	struct list_head list;
41 	interrupt_handler handler;
42 	void *handler_arg;
43 
44 	/* DM which this handler belongs to */
45 	struct amdgpu_display_manager *dm;
46 };
47 
48 struct amdgpu_dm_irq_handler_data {
49 	struct handler_common_data hcd;
50 	/* DAL irq source which registered for this interrupt. */
51 	enum dc_irq_source irq_source;
52 };
53 
54 struct amdgpu_dm_timer_handler_data {
55 	struct handler_common_data hcd;
56 	struct delayed_work d_work;
57 };
58 
59 #define DM_IRQ_TABLE_LOCK(adev, flags) \
60 	spin_lock_irqsave(&adev->dm.irq_handler_list_table_lock, flags)
61 
62 #define DM_IRQ_TABLE_UNLOCK(adev, flags) \
63 	spin_unlock_irqrestore(&adev->dm.irq_handler_list_table_lock, flags)
64 
65 /******************************************************************************
66  * Private functions.
67  *****************************************************************************/
68 
69 static void init_handler_common_data(struct handler_common_data *hcd,
70 				     void (*ih)(void *),
71 				     void *args,
72 				     struct amdgpu_display_manager *dm)
73 {
74 	hcd->handler = ih;
75 	hcd->handler_arg = args;
76 	hcd->dm = dm;
77 }
78 
79 /**
80  * dm_irq_work_func - Handle an IRQ outside of the interrupt handler proper.
81  *
82  * @work: work struct
83  */
84 static void dm_irq_work_func(struct work_struct *work)
85 {
86 	struct list_head *entry;
87 	struct irq_list_head *irq_list_head =
88 		container_of(work, struct irq_list_head, work);
89 	struct list_head *handler_list = &irq_list_head->head;
90 	struct amdgpu_dm_irq_handler_data *handler_data;
91 
92 	list_for_each(entry, handler_list) {
93 		handler_data =
94 			list_entry(
95 				entry,
96 				struct amdgpu_dm_irq_handler_data,
97 				hcd.list);
98 
99 		DRM_DEBUG_KMS("DM_IRQ: work_func: for dal_src=%d\n",
100 				handler_data->irq_source);
101 
102 		DRM_DEBUG_KMS("DM_IRQ: schedule_work: for dal_src=%d\n",
103 			handler_data->irq_source);
104 
105 		handler_data->hcd.handler(handler_data->hcd.handler_arg);
106 	}
107 
108 	/* Call a DAL subcomponent which registered for interrupt notification
109 	 * at INTERRUPT_LOW_IRQ_CONTEXT.
110 	 * (The most common use is HPD interrupt) */
111 }
112 
113 /**
114  * Remove a handler and return a pointer to hander list from which the
115  * handler was removed.
116  */
117 static struct list_head *remove_irq_handler(struct amdgpu_device *adev,
118 					    void *ih,
119 					    const struct dc_interrupt_params *int_params)
120 {
121 	struct list_head *hnd_list;
122 	struct list_head *entry, *tmp;
123 	struct amdgpu_dm_irq_handler_data *handler;
124 	unsigned long irq_table_flags;
125 	bool handler_removed = false;
126 	enum dc_irq_source irq_source;
127 
128 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
129 
130 	irq_source = int_params->irq_source;
131 
132 	switch (int_params->int_context) {
133 	case INTERRUPT_HIGH_IRQ_CONTEXT:
134 		hnd_list = &adev->dm.irq_handler_list_high_tab[irq_source];
135 		break;
136 	case INTERRUPT_LOW_IRQ_CONTEXT:
137 	default:
138 		hnd_list = &adev->dm.irq_handler_list_low_tab[irq_source].head;
139 		break;
140 	}
141 
142 	list_for_each_safe(entry, tmp, hnd_list) {
143 
144 		handler = list_entry(entry, struct amdgpu_dm_irq_handler_data,
145 				hcd.list);
146 
147 		if (ih == handler) {
148 			/* Found our handler. Remove it from the list. */
149 			list_del(&handler->hcd.list);
150 			handler_removed = true;
151 			break;
152 		}
153 	}
154 
155 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
156 
157 	if (handler_removed == false) {
158 		/* Not necessarily an error - caller may not
159 		 * know the context. */
160 		return NULL;
161 	}
162 
163 	kfree(handler);
164 
165 	DRM_DEBUG_KMS(
166 	"DM_IRQ: removed irq handler: %p for: dal_src=%d, irq context=%d\n",
167 		ih, int_params->irq_source, int_params->int_context);
168 
169 	return hnd_list;
170 }
171 
172 /* If 'handler_in == NULL' then remove ALL handlers. */
173 static void remove_timer_handler(struct amdgpu_device *adev,
174 				 struct amdgpu_dm_timer_handler_data *handler_in)
175 {
176 	struct amdgpu_dm_timer_handler_data *handler_temp;
177 	struct list_head *handler_list;
178 	struct list_head *entry, *tmp;
179 	unsigned long irq_table_flags;
180 	bool handler_removed = false;
181 
182 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
183 
184 	handler_list = &adev->dm.timer_handler_list;
185 
186 	list_for_each_safe(entry, tmp, handler_list) {
187 		/* Note that list_for_each_safe() guarantees that
188 		 * handler_temp is NOT null. */
189 		handler_temp = list_entry(entry,
190 				struct amdgpu_dm_timer_handler_data, hcd.list);
191 
192 		if (handler_in == NULL || handler_in == handler_temp) {
193 			list_del(&handler_temp->hcd.list);
194 			DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
195 
196 			DRM_DEBUG_KMS("DM_IRQ: removing timer handler: %p\n",
197 					handler_temp);
198 
199 			if (handler_in == NULL) {
200 				/* Since it is still in the queue, it must
201 				 * be cancelled. */
202 				cancel_delayed_work_sync(&handler_temp->d_work);
203 			}
204 
205 			kfree(handler_temp);
206 			handler_removed = true;
207 
208 			DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
209 		}
210 
211 		/* Remove ALL handlers. */
212 		if (handler_in == NULL)
213 			continue;
214 
215 		/* Remove a SPECIFIC handler.
216 		 * Found our handler - we can stop here. */
217 		if (handler_in == handler_temp)
218 			break;
219 	}
220 
221 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
222 
223 	if (handler_in != NULL && handler_removed == false)
224 		DRM_ERROR("DM_IRQ: handler: %p is not in the list!\n",
225 				handler_in);
226 }
227 
228 static bool
229 validate_irq_registration_params(struct dc_interrupt_params *int_params,
230 				 void (*ih)(void *))
231 {
232 	if (NULL == int_params || NULL == ih) {
233 		DRM_ERROR("DM_IRQ: invalid input!\n");
234 		return false;
235 	}
236 
237 	if (int_params->int_context >= INTERRUPT_CONTEXT_NUMBER) {
238 		DRM_ERROR("DM_IRQ: invalid context: %d!\n",
239 				int_params->int_context);
240 		return false;
241 	}
242 
243 	if (!DAL_VALID_IRQ_SRC_NUM(int_params->irq_source)) {
244 		DRM_ERROR("DM_IRQ: invalid irq_source: %d!\n",
245 				int_params->irq_source);
246 		return false;
247 	}
248 
249 	return true;
250 }
251 
252 static bool validate_irq_unregistration_params(enum dc_irq_source irq_source,
253 					       irq_handler_idx handler_idx)
254 {
255 	if (DAL_INVALID_IRQ_HANDLER_IDX == handler_idx) {
256 		DRM_ERROR("DM_IRQ: invalid handler_idx==NULL!\n");
257 		return false;
258 	}
259 
260 	if (!DAL_VALID_IRQ_SRC_NUM(irq_source)) {
261 		DRM_ERROR("DM_IRQ: invalid irq_source:%d!\n", irq_source);
262 		return false;
263 	}
264 
265 	return true;
266 }
267 /******************************************************************************
268  * Public functions.
269  *
270  * Note: caller is responsible for input validation.
271  *****************************************************************************/
272 
273 void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev,
274 				       struct dc_interrupt_params *int_params,
275 				       void (*ih)(void *),
276 				       void *handler_args)
277 {
278 	struct list_head *hnd_list;
279 	struct amdgpu_dm_irq_handler_data *handler_data;
280 	unsigned long irq_table_flags;
281 	enum dc_irq_source irq_source;
282 
283 	if (false == validate_irq_registration_params(int_params, ih))
284 		return DAL_INVALID_IRQ_HANDLER_IDX;
285 
286 	handler_data = kzalloc(sizeof(*handler_data), GFP_KERNEL);
287 	if (!handler_data) {
288 		DRM_ERROR("DM_IRQ: failed to allocate irq handler!\n");
289 		return DAL_INVALID_IRQ_HANDLER_IDX;
290 	}
291 
292 	memset(handler_data, 0, sizeof(*handler_data));
293 
294 	init_handler_common_data(&handler_data->hcd, ih, handler_args,
295 			&adev->dm);
296 
297 	irq_source = int_params->irq_source;
298 
299 	handler_data->irq_source = irq_source;
300 
301 	/* Lock the list, add the handler. */
302 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
303 
304 	switch (int_params->int_context) {
305 	case INTERRUPT_HIGH_IRQ_CONTEXT:
306 		hnd_list = &adev->dm.irq_handler_list_high_tab[irq_source];
307 		break;
308 	case INTERRUPT_LOW_IRQ_CONTEXT:
309 	default:
310 		hnd_list = &adev->dm.irq_handler_list_low_tab[irq_source].head;
311 		break;
312 	}
313 
314 	list_add_tail(&handler_data->hcd.list, hnd_list);
315 
316 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
317 
318 	/* This pointer will be stored by code which requested interrupt
319 	 * registration.
320 	 * The same pointer will be needed in order to unregister the
321 	 * interrupt. */
322 
323 	DRM_DEBUG_KMS(
324 		"DM_IRQ: added irq handler: %p for: dal_src=%d, irq context=%d\n",
325 		handler_data,
326 		irq_source,
327 		int_params->int_context);
328 
329 	return handler_data;
330 }
331 
332 void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
333 					enum dc_irq_source irq_source,
334 					void *ih)
335 {
336 	struct list_head *handler_list;
337 	struct dc_interrupt_params int_params;
338 	int i;
339 
340 	if (false == validate_irq_unregistration_params(irq_source, ih))
341 		return;
342 
343 	memset(&int_params, 0, sizeof(int_params));
344 
345 	int_params.irq_source = irq_source;
346 
347 	for (i = 0; i < INTERRUPT_CONTEXT_NUMBER; i++) {
348 
349 		int_params.int_context = i;
350 
351 		handler_list = remove_irq_handler(adev, ih, &int_params);
352 
353 		if (handler_list != NULL)
354 			break;
355 	}
356 
357 	if (handler_list == NULL) {
358 		/* If we got here, it means we searched all irq contexts
359 		 * for this irq source, but the handler was not found. */
360 		DRM_ERROR(
361 		"DM_IRQ: failed to find irq handler:%p for irq_source:%d!\n",
362 			ih, irq_source);
363 	}
364 }
365 
366 int amdgpu_dm_irq_init(struct amdgpu_device *adev)
367 {
368 	int src;
369 	struct irq_list_head *lh;
370 
371 	DRM_DEBUG_KMS("DM_IRQ\n");
372 
373 	spin_lock_init(&adev->dm.irq_handler_list_table_lock);
374 
375 	for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) {
376 		/* low context handler list init */
377 		lh = &adev->dm.irq_handler_list_low_tab[src];
378 		INIT_LIST_HEAD(&lh->head);
379 		INIT_WORK(&lh->work, dm_irq_work_func);
380 
381 		/* high context handler init */
382 		INIT_LIST_HEAD(&adev->dm.irq_handler_list_high_tab[src]);
383 	}
384 
385 	INIT_LIST_HEAD(&adev->dm.timer_handler_list);
386 
387 	/* allocate and initialize the workqueue for DM timer */
388 	adev->dm.timer_workqueue = create_singlethread_workqueue(
389 			"dm_timer_queue");
390 	if (adev->dm.timer_workqueue == NULL) {
391 		DRM_ERROR("DM_IRQ: unable to create timer queue!\n");
392 		return -1;
393 	}
394 
395 	return 0;
396 }
397 
398 /* DM IRQ and timer resource release */
399 void amdgpu_dm_irq_fini(struct amdgpu_device *adev)
400 {
401 	int src;
402 	struct irq_list_head *lh;
403 	DRM_DEBUG_KMS("DM_IRQ: releasing resources.\n");
404 
405 	for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) {
406 
407 		/* The handler was removed from the table,
408 		 * it means it is safe to flush all the 'work'
409 		 * (because no code can schedule a new one). */
410 		lh = &adev->dm.irq_handler_list_low_tab[src];
411 		flush_work(&lh->work);
412 	}
413 
414 	/* Cancel ALL timers and release handlers (if any). */
415 	remove_timer_handler(adev, NULL);
416 	/* Release the queue itself. */
417 	destroy_workqueue(adev->dm.timer_workqueue);
418 }
419 
420 int amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
421 {
422 	int src;
423 	struct list_head *hnd_list_h;
424 	struct list_head *hnd_list_l;
425 	unsigned long irq_table_flags;
426 
427 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
428 
429 	DRM_DEBUG_KMS("DM_IRQ: suspend\n");
430 
431 	/**
432 	 * Disable HW interrupt  for HPD and HPDRX only since FLIP and VBLANK
433 	 * will be disabled from manage_dm_interrupts on disable CRTC.
434 	 */
435 	for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
436 		hnd_list_l = &adev->dm.irq_handler_list_low_tab[src].head;
437 		hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
438 		if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
439 			dc_interrupt_set(adev->dm.dc, src, false);
440 
441 		DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
442 		flush_work(&adev->dm.irq_handler_list_low_tab[src].work);
443 
444 		DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
445 	}
446 
447 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
448 	return 0;
449 }
450 
451 int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
452 {
453 	int src;
454 	struct list_head *hnd_list_h, *hnd_list_l;
455 	unsigned long irq_table_flags;
456 
457 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
458 
459 	DRM_DEBUG_KMS("DM_IRQ: early resume\n");
460 
461 	/* re-enable short pulse interrupts HW interrupt */
462 	for (src = DC_IRQ_SOURCE_HPD1RX; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
463 		hnd_list_l = &adev->dm.irq_handler_list_low_tab[src].head;
464 		hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
465 		if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
466 			dc_interrupt_set(adev->dm.dc, src, true);
467 	}
468 
469 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
470 
471 	return 0;
472 }
473 
474 int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
475 {
476 	int src;
477 	struct list_head *hnd_list_h, *hnd_list_l;
478 	unsigned long irq_table_flags;
479 
480 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
481 
482 	DRM_DEBUG_KMS("DM_IRQ: resume\n");
483 
484 	/**
485 	 * Renable HW interrupt  for HPD and only since FLIP and VBLANK
486 	 * will be enabled from manage_dm_interrupts on enable CRTC.
487 	 */
488 	for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6; src++) {
489 		hnd_list_l = &adev->dm.irq_handler_list_low_tab[src].head;
490 		hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
491 		if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
492 			dc_interrupt_set(adev->dm.dc, src, true);
493 	}
494 
495 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
496 	return 0;
497 }
498 
499 /**
500  * amdgpu_dm_irq_schedule_work - schedule all work items registered for the
501  * "irq_source".
502  */
503 static void amdgpu_dm_irq_schedule_work(struct amdgpu_device *adev,
504 					enum dc_irq_source irq_source)
505 {
506 	unsigned long irq_table_flags;
507 	struct work_struct *work = NULL;
508 
509 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
510 
511 	if (!list_empty(&adev->dm.irq_handler_list_low_tab[irq_source].head))
512 		work = &adev->dm.irq_handler_list_low_tab[irq_source].work;
513 
514 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
515 
516 	if (work) {
517 		if (!schedule_work(work))
518 			DRM_INFO("amdgpu_dm_irq_schedule_work FAILED src %d\n",
519 						irq_source);
520 	}
521 
522 }
523 
524 /** amdgpu_dm_irq_immediate_work
525  *  Callback high irq work immediately, don't send to work queue
526  */
527 static void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
528 					 enum dc_irq_source irq_source)
529 {
530 	struct amdgpu_dm_irq_handler_data *handler_data;
531 	struct list_head *entry;
532 	unsigned long irq_table_flags;
533 
534 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
535 
536 	list_for_each(
537 		entry,
538 		&adev->dm.irq_handler_list_high_tab[irq_source]) {
539 
540 		handler_data =
541 			list_entry(
542 				entry,
543 				struct amdgpu_dm_irq_handler_data,
544 				hcd.list);
545 
546 		/* Call a subcomponent which registered for immediate
547 		 * interrupt notification */
548 		handler_data->hcd.handler(handler_data->hcd.handler_arg);
549 	}
550 
551 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
552 }
553 
554 /*
555  * amdgpu_dm_irq_handler
556  *
557  * Generic IRQ handler, calls all registered high irq work immediately, and
558  * schedules work for low irq
559  */
560 static int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
561 				 struct amdgpu_irq_src *source,
562 				 struct amdgpu_iv_entry *entry)
563 {
564 
565 	enum dc_irq_source src =
566 		dc_interrupt_to_irq_source(
567 			adev->dm.dc,
568 			entry->src_id,
569 			entry->src_data[0]);
570 
571 	dc_interrupt_ack(adev->dm.dc, src);
572 
573 	/* Call high irq work immediately */
574 	amdgpu_dm_irq_immediate_work(adev, src);
575 	/*Schedule low_irq work */
576 	amdgpu_dm_irq_schedule_work(adev, src);
577 
578 	return 0;
579 }
580 
581 static enum dc_irq_source amdgpu_dm_hpd_to_dal_irq_source(unsigned type)
582 {
583 	switch (type) {
584 	case AMDGPU_HPD_1:
585 		return DC_IRQ_SOURCE_HPD1;
586 	case AMDGPU_HPD_2:
587 		return DC_IRQ_SOURCE_HPD2;
588 	case AMDGPU_HPD_3:
589 		return DC_IRQ_SOURCE_HPD3;
590 	case AMDGPU_HPD_4:
591 		return DC_IRQ_SOURCE_HPD4;
592 	case AMDGPU_HPD_5:
593 		return DC_IRQ_SOURCE_HPD5;
594 	case AMDGPU_HPD_6:
595 		return DC_IRQ_SOURCE_HPD6;
596 	default:
597 		return DC_IRQ_SOURCE_INVALID;
598 	}
599 }
600 
601 static int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev,
602 				       struct amdgpu_irq_src *source,
603 				       unsigned type,
604 				       enum amdgpu_interrupt_state state)
605 {
606 	enum dc_irq_source src = amdgpu_dm_hpd_to_dal_irq_source(type);
607 	bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
608 
609 	dc_interrupt_set(adev->dm.dc, src, st);
610 	return 0;
611 }
612 
613 static inline int dm_irq_state(struct amdgpu_device *adev,
614 			       struct amdgpu_irq_src *source,
615 			       unsigned crtc_id,
616 			       enum amdgpu_interrupt_state state,
617 			       const enum irq_type dal_irq_type,
618 			       const char *func)
619 {
620 	bool st;
621 	enum dc_irq_source irq_source;
622 
623 	struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc_id];
624 
625 	if (!acrtc) {
626 		DRM_ERROR(
627 			"%s: crtc is NULL at id :%d\n",
628 			func,
629 			crtc_id);
630 		return 0;
631 	}
632 
633 	irq_source = dal_irq_type + acrtc->otg_inst;
634 
635 	st = (state == AMDGPU_IRQ_STATE_ENABLE);
636 
637 	dc_interrupt_set(adev->dm.dc, irq_source, st);
638 	return 0;
639 }
640 
641 static int amdgpu_dm_set_pflip_irq_state(struct amdgpu_device *adev,
642 					 struct amdgpu_irq_src *source,
643 					 unsigned crtc_id,
644 					 enum amdgpu_interrupt_state state)
645 {
646 	return dm_irq_state(
647 		adev,
648 		source,
649 		crtc_id,
650 		state,
651 		IRQ_TYPE_PFLIP,
652 		__func__);
653 }
654 
655 static int amdgpu_dm_set_crtc_irq_state(struct amdgpu_device *adev,
656 					struct amdgpu_irq_src *source,
657 					unsigned crtc_id,
658 					enum amdgpu_interrupt_state state)
659 {
660 	return dm_irq_state(
661 		adev,
662 		source,
663 		crtc_id,
664 		state,
665 		IRQ_TYPE_VBLANK,
666 		__func__);
667 }
668 
669 static const struct amdgpu_irq_src_funcs dm_crtc_irq_funcs = {
670 	.set = amdgpu_dm_set_crtc_irq_state,
671 	.process = amdgpu_dm_irq_handler,
672 };
673 
674 static const struct amdgpu_irq_src_funcs dm_pageflip_irq_funcs = {
675 	.set = amdgpu_dm_set_pflip_irq_state,
676 	.process = amdgpu_dm_irq_handler,
677 };
678 
679 static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = {
680 	.set = amdgpu_dm_set_hpd_irq_state,
681 	.process = amdgpu_dm_irq_handler,
682 };
683 
684 void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
685 {
686 	adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST;
687 	adev->crtc_irq.funcs = &dm_crtc_irq_funcs;
688 
689 	adev->pageflip_irq.num_types = AMDGPU_PAGEFLIP_IRQ_LAST;
690 	adev->pageflip_irq.funcs = &dm_pageflip_irq_funcs;
691 
692 	adev->hpd_irq.num_types = AMDGPU_HPD_LAST;
693 	adev->hpd_irq.funcs = &dm_hpd_irq_funcs;
694 }
695 
696 /*
697  * amdgpu_dm_hpd_init - hpd setup callback.
698  *
699  * @adev: amdgpu_device pointer
700  *
701  * Setup the hpd pins used by the card (evergreen+).
702  * Enable the pin, set the polarity, and enable the hpd interrupts.
703  */
704 void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
705 {
706 	struct drm_device *dev = adev->ddev;
707 	struct drm_connector *connector;
708 
709 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
710 		struct amdgpu_dm_connector *amdgpu_dm_connector =
711 				to_amdgpu_dm_connector(connector);
712 
713 		const struct dc_link *dc_link = amdgpu_dm_connector->dc_link;
714 
715 		if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd) {
716 			dc_interrupt_set(adev->dm.dc,
717 					dc_link->irq_source_hpd,
718 					true);
719 		}
720 
721 		if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd_rx) {
722 			dc_interrupt_set(adev->dm.dc,
723 					dc_link->irq_source_hpd_rx,
724 					true);
725 		}
726 	}
727 }
728 
729 /**
730  * amdgpu_dm_hpd_fini - hpd tear down callback.
731  *
732  * @adev: amdgpu_device pointer
733  *
734  * Tear down the hpd pins used by the card (evergreen+).
735  * Disable the hpd interrupts.
736  */
737 void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
738 {
739 	struct drm_device *dev = adev->ddev;
740 	struct drm_connector *connector;
741 
742 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
743 		struct amdgpu_dm_connector *amdgpu_dm_connector =
744 				to_amdgpu_dm_connector(connector);
745 		const struct dc_link *dc_link = amdgpu_dm_connector->dc_link;
746 
747 		dc_interrupt_set(adev->dm.dc, dc_link->irq_source_hpd, false);
748 
749 		if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd_rx) {
750 			dc_interrupt_set(adev->dm.dc,
751 					dc_link->irq_source_hpd_rx,
752 					false);
753 		}
754 	}
755 }
756