2 * drivers/gpu/drm/omapdrm/omap_irq.c
4 * Copyright (C) 2012 Texas Instruments
5 * Author: Rob Clark <rob.clark@linaro.org>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
22 static DEFINE_SPINLOCK(list_lock
);
24 static void omap_irq_error_handler(struct omap_drm_irq
*irq
,
27 DRM_ERROR("errors: %08x\n", irqstatus
);
30 /* call with list_lock and dispc runtime held */
31 static void omap_irq_update(struct drm_device
*dev
)
33 struct omap_drm_private
*priv
= dev
->dev_private
;
34 struct omap_drm_irq
*irq
;
35 uint32_t irqmask
= priv
->vblank_mask
;
37 BUG_ON(!spin_is_locked(&list_lock
));
39 list_for_each_entry(irq
, &priv
->irq_list
, node
)
40 irqmask
|= irq
->irqmask
;
42 DBG("irqmask=%08x", irqmask
);
44 dispc_write_irqenable(irqmask
);
45 dispc_read_irqenable(); /* flush posted write */
48 void __omap_irq_register(struct drm_device
*dev
, struct omap_drm_irq
*irq
)
50 struct omap_drm_private
*priv
= dev
->dev_private
;
53 spin_lock_irqsave(&list_lock
, flags
);
55 if (!WARN_ON(irq
->registered
)) {
56 irq
->registered
= true;
57 list_add(&irq
->node
, &priv
->irq_list
);
61 spin_unlock_irqrestore(&list_lock
, flags
);
64 void omap_irq_register(struct drm_device
*dev
, struct omap_drm_irq
*irq
)
68 __omap_irq_register(dev
, irq
);
73 void __omap_irq_unregister(struct drm_device
*dev
, struct omap_drm_irq
*irq
)
77 spin_lock_irqsave(&list_lock
, flags
);
79 if (!WARN_ON(!irq
->registered
)) {
80 irq
->registered
= false;
85 spin_unlock_irqrestore(&list_lock
, flags
);
88 void omap_irq_unregister(struct drm_device
*dev
, struct omap_drm_irq
*irq
)
92 __omap_irq_unregister(dev
, irq
);
97 struct omap_irq_wait
{
98 struct omap_drm_irq irq
;
102 static DECLARE_WAIT_QUEUE_HEAD(wait_event
);
104 static void wait_irq(struct omap_drm_irq
*irq
, uint32_t irqstatus
)
106 struct omap_irq_wait
*wait
=
107 container_of(irq
, struct omap_irq_wait
, irq
);
109 wake_up_all(&wait_event
);
112 struct omap_irq_wait
* omap_irq_wait_init(struct drm_device
*dev
,
113 uint32_t irqmask
, int count
)
115 struct omap_irq_wait
*wait
= kzalloc(sizeof(*wait
), GFP_KERNEL
);
116 wait
->irq
.irq
= wait_irq
;
117 wait
->irq
.irqmask
= irqmask
;
119 omap_irq_register(dev
, &wait
->irq
);
123 int omap_irq_wait(struct drm_device
*dev
, struct omap_irq_wait
*wait
,
124 unsigned long timeout
)
126 int ret
= wait_event_timeout(wait_event
, (wait
->count
<= 0), timeout
);
127 omap_irq_unregister(dev
, &wait
->irq
);
135 * enable_vblank - enable vblank interrupt events
137 * @crtc: which irq to enable
139 * Enable vblank interrupts for @crtc. If the device doesn't have
140 * a hardware vblank counter, this routine should be a no-op, since
141 * interrupts will have to stay on to keep the count accurate.
144 * Zero on success, appropriate errno if the given @crtc's vblank
145 * interrupt cannot be enabled.
147 int omap_irq_enable_vblank(struct drm_device
*dev
, int crtc_id
)
149 struct omap_drm_private
*priv
= dev
->dev_private
;
150 struct drm_crtc
*crtc
= priv
->crtcs
[crtc_id
];
153 DBG("dev=%p, crtc=%d", dev
, crtc_id
);
156 spin_lock_irqsave(&list_lock
, flags
);
157 priv
->vblank_mask
|= pipe2vbl(crtc
);
158 omap_irq_update(dev
);
159 spin_unlock_irqrestore(&list_lock
, flags
);
166 * disable_vblank - disable vblank interrupt events
168 * @crtc: which irq to enable
170 * Disable vblank interrupts for @crtc. If the device doesn't have
171 * a hardware vblank counter, this routine should be a no-op, since
172 * interrupts will have to stay on to keep the count accurate.
174 void omap_irq_disable_vblank(struct drm_device
*dev
, int crtc_id
)
176 struct omap_drm_private
*priv
= dev
->dev_private
;
177 struct drm_crtc
*crtc
= priv
->crtcs
[crtc_id
];
180 DBG("dev=%p, crtc=%d", dev
, crtc_id
);
183 spin_lock_irqsave(&list_lock
, flags
);
184 priv
->vblank_mask
&= ~pipe2vbl(crtc
);
185 omap_irq_update(dev
);
186 spin_unlock_irqrestore(&list_lock
, flags
);
190 irqreturn_t
omap_irq_handler(int irq
, void *arg
)
192 struct drm_device
*dev
= (struct drm_device
*) arg
;
193 struct omap_drm_private
*priv
= dev
->dev_private
;
194 struct omap_drm_irq
*handler
, *n
;
199 irqstatus
= dispc_read_irqstatus();
200 dispc_clear_irqstatus(irqstatus
);
201 dispc_read_irqstatus(); /* flush posted write */
203 VERB("irqs: %08x", irqstatus
);
205 for (id
= 0; id
< priv
->num_crtcs
; id
++) {
206 struct drm_crtc
*crtc
= priv
->crtcs
[id
];
208 if (irqstatus
& pipe2vbl(crtc
))
209 drm_handle_vblank(dev
, id
);
212 spin_lock_irqsave(&list_lock
, flags
);
213 list_for_each_entry_safe(handler
, n
, &priv
->irq_list
, node
) {
214 if (handler
->irqmask
& irqstatus
) {
215 spin_unlock_irqrestore(&list_lock
, flags
);
216 handler
->irq(handler
, handler
->irqmask
& irqstatus
);
217 spin_lock_irqsave(&list_lock
, flags
);
220 spin_unlock_irqrestore(&list_lock
, flags
);
225 void omap_irq_preinstall(struct drm_device
*dev
)
229 dispc_clear_irqstatus(0xffffffff);
233 int omap_irq_postinstall(struct drm_device
*dev
)
235 struct omap_drm_private
*priv
= dev
->dev_private
;
236 struct omap_drm_irq
*error_handler
= &priv
->error_handler
;
240 INIT_LIST_HEAD(&priv
->irq_list
);
242 error_handler
->irq
= omap_irq_error_handler
;
243 error_handler
->irqmask
= DISPC_IRQ_OCP_ERR
;
245 /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think
246 * we just need to ignore it while enabling tv-out
248 error_handler
->irqmask
&= ~DISPC_IRQ_SYNC_LOST_DIGIT
;
250 omap_irq_register(dev
, error_handler
);
255 void omap_irq_uninstall(struct drm_device
*dev
)
258 // TODO prolly need to call drm_irq_uninstall() somewhere too
262 * We need a special version, instead of just using drm_irq_install(),
263 * because we need to register the irq via omapdss. Once omapdss and
264 * omapdrm are merged together we can assign the dispc hwmod data to
265 * ourselves and drop these and just use drm_irq_{install,uninstall}()
268 int omap_drm_irq_install(struct drm_device
*dev
)
272 mutex_lock(&dev
->struct_mutex
);
274 if (dev
->irq_enabled
) {
275 mutex_unlock(&dev
->struct_mutex
);
278 dev
->irq_enabled
= true;
279 mutex_unlock(&dev
->struct_mutex
);
281 /* Before installing handler */
282 if (dev
->driver
->irq_preinstall
)
283 dev
->driver
->irq_preinstall(dev
);
285 ret
= dispc_request_irq(dev
->driver
->irq_handler
, dev
);
288 mutex_lock(&dev
->struct_mutex
);
289 dev
->irq_enabled
= false;
290 mutex_unlock(&dev
->struct_mutex
);
294 /* After installing handler */
295 if (dev
->driver
->irq_postinstall
)
296 ret
= dev
->driver
->irq_postinstall(dev
);
299 mutex_lock(&dev
->struct_mutex
);
300 dev
->irq_enabled
= false;
301 mutex_unlock(&dev
->struct_mutex
);
308 int omap_drm_irq_uninstall(struct drm_device
*dev
)
310 unsigned long irqflags
;
314 mutex_lock(&dev
->struct_mutex
);
315 irq_enabled
= dev
->irq_enabled
;
316 dev
->irq_enabled
= false;
317 mutex_unlock(&dev
->struct_mutex
);
320 * Wake up any waiters so they don't hang.
322 if (dev
->num_crtcs
) {
323 spin_lock_irqsave(&dev
->vbl_lock
, irqflags
);
324 for (i
= 0; i
< dev
->num_crtcs
; i
++) {
325 wake_up(&dev
->vblank
[i
].queue
);
326 dev
->vblank
[i
].enabled
= false;
327 dev
->vblank
[i
].last
=
328 dev
->driver
->get_vblank_counter(dev
, i
);
330 spin_unlock_irqrestore(&dev
->vbl_lock
, irqflags
);
336 if (dev
->driver
->irq_uninstall
)
337 dev
->driver
->irq_uninstall(dev
);