]> Git Repo - linux.git/blob - drivers/gpu/drm/tidss/tidss_irq.c
Merge tag 'for-linus' of https://github.com/openrisc/linux
[linux.git] / drivers / gpu / drm / tidss / tidss_irq.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
4  * Author: Tomi Valkeinen <[email protected]>
5  */
6
7 #include <linux/platform_device.h>
8
9 #include <drm/drm_drv.h>
10 #include <drm/drm_print.h>
11
12 #include "tidss_crtc.h"
13 #include "tidss_dispc.h"
14 #include "tidss_drv.h"
15 #include "tidss_irq.h"
16 #include "tidss_plane.h"
17
18 static void tidss_irq_update(struct tidss_device *tidss)
19 {
20         assert_spin_locked(&tidss->irq_lock);
21
22         dispc_set_irqenable(tidss->dispc, tidss->irq_mask);
23 }
24
25 void tidss_irq_enable_vblank(struct drm_crtc *crtc)
26 {
27         struct drm_device *ddev = crtc->dev;
28         struct tidss_device *tidss = to_tidss(ddev);
29         struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
30         u32 hw_videoport = tcrtc->hw_videoport;
31         unsigned long flags;
32
33         spin_lock_irqsave(&tidss->irq_lock, flags);
34         tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
35                            DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
36         tidss_irq_update(tidss);
37         spin_unlock_irqrestore(&tidss->irq_lock, flags);
38 }
39
40 void tidss_irq_disable_vblank(struct drm_crtc *crtc)
41 {
42         struct drm_device *ddev = crtc->dev;
43         struct tidss_device *tidss = to_tidss(ddev);
44         struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
45         u32 hw_videoport = tcrtc->hw_videoport;
46         unsigned long flags;
47
48         spin_lock_irqsave(&tidss->irq_lock, flags);
49         tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
50                              DSS_IRQ_VP_VSYNC_ODD(hw_videoport));
51         tidss_irq_update(tidss);
52         spin_unlock_irqrestore(&tidss->irq_lock, flags);
53 }
54
55 static irqreturn_t tidss_irq_handler(int irq, void *arg)
56 {
57         struct drm_device *ddev = (struct drm_device *)arg;
58         struct tidss_device *tidss = to_tidss(ddev);
59         unsigned int id;
60         dispc_irq_t irqstatus;
61
62         spin_lock(&tidss->irq_lock);
63         irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);
64         spin_unlock(&tidss->irq_lock);
65
66         for (id = 0; id < tidss->num_crtcs; id++) {
67                 struct drm_crtc *crtc = tidss->crtcs[id];
68                 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
69                 u32 hw_videoport = tcrtc->hw_videoport;
70
71                 if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
72                                  DSS_IRQ_VP_VSYNC_ODD(hw_videoport)))
73                         tidss_crtc_vblank_irq(crtc);
74
75                 if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport)))
76                         tidss_crtc_framedone_irq(crtc);
77
78                 if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
79                         tidss_crtc_error_irq(crtc, irqstatus);
80         }
81
82         for (unsigned int i = 0; i < tidss->num_planes; ++i) {
83                 struct drm_plane *plane = tidss->planes[i];
84                 struct tidss_plane *tplane = to_tidss_plane(plane);
85
86                 if (irqstatus & DSS_IRQ_PLANE_FIFO_UNDERFLOW(tplane->hw_plane_id))
87                         tidss_plane_error_irq(plane, irqstatus);
88         }
89
90         return IRQ_HANDLED;
91 }
92
93 void tidss_irq_resume(struct tidss_device *tidss)
94 {
95         unsigned long flags;
96
97         spin_lock_irqsave(&tidss->irq_lock, flags);
98         tidss_irq_update(tidss);
99         spin_unlock_irqrestore(&tidss->irq_lock, flags);
100 }
101
102 int tidss_irq_install(struct drm_device *ddev, unsigned int irq)
103 {
104         struct tidss_device *tidss = to_tidss(ddev);
105         int ret;
106
107         if (irq == IRQ_NOTCONNECTED)
108                 return -ENOTCONN;
109
110         ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev);
111         if (ret)
112                 return ret;
113
114         tidss->irq_mask = 0;
115
116         for (unsigned int i = 0; i < tidss->num_crtcs; ++i) {
117                 struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]);
118
119                 tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport);
120
121                 tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport);
122         }
123
124         for (unsigned int i = 0; i < tidss->num_planes; ++i) {
125                 struct tidss_plane *tplane = to_tidss_plane(tidss->planes[i]);
126
127                 tidss->irq_mask |= DSS_IRQ_PLANE_FIFO_UNDERFLOW(tplane->hw_plane_id);
128         }
129
130         return 0;
131 }
132
133 void tidss_irq_uninstall(struct drm_device *ddev)
134 {
135         struct tidss_device *tidss = to_tidss(ddev);
136
137         free_irq(tidss->irq, ddev);
138 }
This page took 0.038172 seconds and 4 git commands to generate.