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
;
54 spin_lock_irqsave(&list_lock
, flags
);
56 if (!WARN_ON(irq
->registered
)) {
57 irq
->registered
= true;
58 list_add(&irq
->node
, &priv
->irq_list
);
62 spin_unlock_irqrestore(&list_lock
, flags
);
66 void omap_irq_unregister(struct drm_device
*dev
, struct omap_drm_irq
*irq
)
71 spin_lock_irqsave(&list_lock
, flags
);
73 if (!WARN_ON(!irq
->registered
)) {
74 irq
->registered
= false;
79 spin_unlock_irqrestore(&list_lock
, flags
);
83 struct omap_irq_wait
{
84 struct omap_drm_irq irq
;
88 static DECLARE_WAIT_QUEUE_HEAD(wait_event
);
90 static void wait_irq(struct omap_drm_irq
*irq
, uint32_t irqstatus
)
92 struct omap_irq_wait
*wait
=
93 container_of(irq
, struct omap_irq_wait
, irq
);
95 wake_up_all(&wait_event
);
98 struct omap_irq_wait
* omap_irq_wait_init(struct drm_device
*dev
,
99 uint32_t irqmask
, int count
)
101 struct omap_irq_wait
*wait
= kzalloc(sizeof(*wait
), GFP_KERNEL
);
102 wait
->irq
.irq
= wait_irq
;
103 wait
->irq
.irqmask
= irqmask
;
105 omap_irq_register(dev
, &wait
->irq
);
109 int omap_irq_wait(struct drm_device
*dev
, struct omap_irq_wait
*wait
,
110 unsigned long timeout
)
112 int ret
= wait_event_timeout(wait_event
, (wait
->count
<= 0), timeout
);
113 omap_irq_unregister(dev
, &wait
->irq
);
121 * enable_vblank - enable vblank interrupt events
123 * @crtc: which irq to enable
125 * Enable vblank interrupts for @crtc. If the device doesn't have
126 * a hardware vblank counter, this routine should be a no-op, since
127 * interrupts will have to stay on to keep the count accurate.
130 * Zero on success, appropriate errno if the given @crtc's vblank
131 * interrupt cannot be enabled.
133 int omap_irq_enable_vblank(struct drm_device
*dev
, int crtc_id
)
135 struct omap_drm_private
*priv
= dev
->dev_private
;
136 struct drm_crtc
*crtc
= priv
->crtcs
[crtc_id
];
139 DBG("dev=%p, crtc=%d", dev
, crtc_id
);
142 spin_lock_irqsave(&list_lock
, flags
);
143 priv
->vblank_mask
|= pipe2vbl(crtc
);
144 omap_irq_update(dev
);
145 spin_unlock_irqrestore(&list_lock
, flags
);
152 * disable_vblank - disable vblank interrupt events
154 * @crtc: which irq to enable
156 * Disable vblank interrupts for @crtc. If the device doesn't have
157 * a hardware vblank counter, this routine should be a no-op, since
158 * interrupts will have to stay on to keep the count accurate.
160 void omap_irq_disable_vblank(struct drm_device
*dev
, int crtc_id
)
162 struct omap_drm_private
*priv
= dev
->dev_private
;
163 struct drm_crtc
*crtc
= priv
->crtcs
[crtc_id
];
166 DBG("dev=%p, crtc=%d", dev
, crtc_id
);
169 spin_lock_irqsave(&list_lock
, flags
);
170 priv
->vblank_mask
&= ~pipe2vbl(crtc
);
171 omap_irq_update(dev
);
172 spin_unlock_irqrestore(&list_lock
, flags
);
176 irqreturn_t
omap_irq_handler(DRM_IRQ_ARGS
)
178 struct drm_device
*dev
= (struct drm_device
*) arg
;
179 struct omap_drm_private
*priv
= dev
->dev_private
;
180 struct omap_drm_irq
*handler
, *n
;
185 irqstatus
= dispc_read_irqstatus();
186 dispc_clear_irqstatus(irqstatus
);
187 dispc_read_irqstatus(); /* flush posted write */
189 VERB("irqs: %08x", irqstatus
);
191 for (id
= 0; id
< priv
->num_crtcs
; id
++) {
192 struct drm_crtc
*crtc
= priv
->crtcs
[id
];
194 if (irqstatus
& pipe2vbl(crtc
))
195 drm_handle_vblank(dev
, id
);
198 spin_lock_irqsave(&list_lock
, flags
);
199 list_for_each_entry_safe(handler
, n
, &priv
->irq_list
, node
) {
200 if (handler
->irqmask
& irqstatus
) {
201 spin_unlock_irqrestore(&list_lock
, flags
);
202 handler
->irq(handler
, handler
->irqmask
& irqstatus
);
203 spin_lock_irqsave(&list_lock
, flags
);
206 spin_unlock_irqrestore(&list_lock
, flags
);
211 void omap_irq_preinstall(struct drm_device
*dev
)
215 dispc_clear_irqstatus(0xffffffff);
219 int omap_irq_postinstall(struct drm_device
*dev
)
221 struct omap_drm_private
*priv
= dev
->dev_private
;
222 struct omap_drm_irq
*error_handler
= &priv
->error_handler
;
226 INIT_LIST_HEAD(&priv
->irq_list
);
228 error_handler
->irq
= omap_irq_error_handler
;
229 error_handler
->irqmask
= DISPC_IRQ_OCP_ERR
;
231 /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think
232 * we just need to ignore it while enabling tv-out
234 error_handler
->irqmask
&= ~DISPC_IRQ_SYNC_LOST_DIGIT
;
236 omap_irq_register(dev
, error_handler
);
241 void omap_irq_uninstall(struct drm_device
*dev
)
244 // TODO prolly need to call drm_irq_uninstall() somewhere too
248 * We need a special version, instead of just using drm_irq_install(),
249 * because we need to register the irq via omapdss. Once omapdss and
250 * omapdrm are merged together we can assign the dispc hwmod data to
251 * ourselves and drop these and just use drm_irq_{install,uninstall}()
254 int omap_drm_irq_install(struct drm_device
*dev
)
258 mutex_lock(&dev
->struct_mutex
);
260 if (dev
->irq_enabled
) {
261 mutex_unlock(&dev
->struct_mutex
);
264 dev
->irq_enabled
= 1;
265 mutex_unlock(&dev
->struct_mutex
);
267 /* Before installing handler */
268 if (dev
->driver
->irq_preinstall
)
269 dev
->driver
->irq_preinstall(dev
);
271 ret
= dispc_request_irq(dev
->driver
->irq_handler
, dev
);
274 mutex_lock(&dev
->struct_mutex
);
275 dev
->irq_enabled
= 0;
276 mutex_unlock(&dev
->struct_mutex
);
280 /* After installing handler */
281 if (dev
->driver
->irq_postinstall
)
282 ret
= dev
->driver
->irq_postinstall(dev
);
285 mutex_lock(&dev
->struct_mutex
);
286 dev
->irq_enabled
= 0;
287 mutex_unlock(&dev
->struct_mutex
);
294 int omap_drm_irq_uninstall(struct drm_device
*dev
)
296 unsigned long irqflags
;
299 mutex_lock(&dev
->struct_mutex
);
300 irq_enabled
= dev
->irq_enabled
;
301 dev
->irq_enabled
= 0;
302 mutex_unlock(&dev
->struct_mutex
);
305 * Wake up any waiters so they don't hang.
307 if (dev
->num_crtcs
) {
308 spin_lock_irqsave(&dev
->vbl_lock
, irqflags
);
309 for (i
= 0; i
< dev
->num_crtcs
; i
++) {
310 DRM_WAKEUP(&dev
->vbl_queue
[i
]);
311 dev
->vblank_enabled
[i
] = 0;
312 dev
->last_vblank
[i
] =
313 dev
->driver
->get_vblank_counter(dev
, i
);
315 spin_unlock_irqrestore(&dev
->vbl_lock
, irqflags
);
321 if (dev
->driver
->irq_uninstall
)
322 dev
->driver
->irq_uninstall(dev
);