1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2023 Loongson Technology Corporation Limited
4 */
5
6 #include <drm/drm_print.h>
7 #include <drm/drm_vblank.h>
8
9 #include "lsdc_irq.h"
10
11 /*
12 * For the DC in LS7A2000, clearing interrupt status is achieved by
13 * write "1" to LSDC_INT_REG.
14 *
15 * For the DC in LS7A1000, clear interrupt status is achieved by write "0"
16 * to LSDC_INT_REG.
17 *
18 * Two different hardware engineers modify it as their will.
19 */
20
ls7a2000_dc_irq_handler(int irq,void * arg)21 irqreturn_t ls7a2000_dc_irq_handler(int irq, void *arg)
22 {
23 struct drm_device *ddev = arg;
24 struct lsdc_device *ldev = to_lsdc(ddev);
25 u32 val;
26
27 /* Read the interrupt status */
28 val = lsdc_rreg32(ldev, LSDC_INT_REG);
29 if ((val & INT_STATUS_MASK) == 0) {
30 drm_warn(ddev, "no interrupt occurs\n");
31 return IRQ_NONE;
32 }
33
34 ldev->irq_status = val;
35
36 /* write "1" to clear the interrupt status */
37 lsdc_wreg32(ldev, LSDC_INT_REG, val);
38
39 if (ldev->irq_status & INT_CRTC0_VSYNC)
40 drm_handle_vblank(ddev, 0);
41
42 if (ldev->irq_status & INT_CRTC1_VSYNC)
43 drm_handle_vblank(ddev, 1);
44
45 return IRQ_HANDLED;
46 }
47
48 /* For the DC in LS7A1000 and LS2K1000 */
ls7a1000_dc_irq_handler(int irq,void * arg)49 irqreturn_t ls7a1000_dc_irq_handler(int irq, void *arg)
50 {
51 struct drm_device *ddev = arg;
52 struct lsdc_device *ldev = to_lsdc(ddev);
53 u32 val;
54
55 /* Read the interrupt status */
56 val = lsdc_rreg32(ldev, LSDC_INT_REG);
57 if ((val & INT_STATUS_MASK) == 0) {
58 drm_warn(ddev, "no interrupt occurs\n");
59 return IRQ_NONE;
60 }
61
62 ldev->irq_status = val;
63
64 /* write "0" to clear the interrupt status */
65 val &= ~(INT_CRTC0_VSYNC | INT_CRTC1_VSYNC);
66 lsdc_wreg32(ldev, LSDC_INT_REG, val);
67
68 if (ldev->irq_status & INT_CRTC0_VSYNC)
69 drm_handle_vblank(ddev, 0);
70
71 if (ldev->irq_status & INT_CRTC1_VSYNC)
72 drm_handle_vblank(ddev, 1);
73
74 return IRQ_HANDLED;
75 }
76