2 * drivers/staging/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
)
135 struct omap_drm_private
*priv
= dev
->dev_private
;
138 DBG("dev=%p, crtc=%d", dev
, crtc
);
141 spin_lock_irqsave(&list_lock
, flags
);
142 priv
->vblank_mask
|= pipe2vbl(crtc
);
143 omap_irq_update(dev
);
144 spin_unlock_irqrestore(&list_lock
, flags
);
151 * disable_vblank - disable vblank interrupt events
153 * @crtc: which irq to enable
155 * Disable vblank interrupts for @crtc. If the device doesn't have
156 * a hardware vblank counter, this routine should be a no-op, since
157 * interrupts will have to stay on to keep the count accurate.
159 void omap_irq_disable_vblank(struct drm_device
*dev
, int crtc
)
161 struct omap_drm_private
*priv
= dev
->dev_private
;
164 DBG("dev=%p, crtc=%d", dev
, crtc
);
167 spin_lock_irqsave(&list_lock
, flags
);
168 priv
->vblank_mask
&= ~pipe2vbl(crtc
);
169 omap_irq_update(dev
);
170 spin_unlock_irqrestore(&list_lock
, flags
);
174 irqreturn_t
omap_irq_handler(DRM_IRQ_ARGS
)
176 struct drm_device
*dev
= (struct drm_device
*) arg
;
177 struct omap_drm_private
*priv
= dev
->dev_private
;
178 struct omap_drm_irq
*handler
, *n
;
183 irqstatus
= dispc_read_irqstatus();
184 dispc_clear_irqstatus(irqstatus
);
185 dispc_read_irqstatus(); /* flush posted write */
187 VERB("irqs: %08x", irqstatus
);
189 for (id
= 0; id
< priv
->num_crtcs
; id
++)
190 if (irqstatus
& pipe2vbl(id
))
191 drm_handle_vblank(dev
, id
);
193 spin_lock_irqsave(&list_lock
, flags
);
194 list_for_each_entry_safe(handler
, n
, &priv
->irq_list
, node
) {
195 if (handler
->irqmask
& irqstatus
) {
196 spin_unlock_irqrestore(&list_lock
, flags
);
197 handler
->irq(handler
, handler
->irqmask
& irqstatus
);
198 spin_lock_irqsave(&list_lock
, flags
);
201 spin_unlock_irqrestore(&list_lock
, flags
);
206 void omap_irq_preinstall(struct drm_device
*dev
)
210 dispc_clear_irqstatus(0xffffffff);
214 int omap_irq_postinstall(struct drm_device
*dev
)
216 struct omap_drm_private
*priv
= dev
->dev_private
;
217 struct omap_drm_irq
*error_handler
= &priv
->error_handler
;
221 INIT_LIST_HEAD(&priv
->irq_list
);
223 error_handler
->irq
= omap_irq_error_handler
;
224 error_handler
->irqmask
= DISPC_IRQ_OCP_ERR
;
226 /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think
227 * we just need to ignore it while enabling tv-out
229 error_handler
->irqmask
&= ~DISPC_IRQ_SYNC_LOST_DIGIT
;
231 omap_irq_register(dev
, error_handler
);
236 void omap_irq_uninstall(struct drm_device
*dev
)
239 // TODO prolly need to call drm_irq_uninstall() somewhere too
243 * We need a special version, instead of just using drm_irq_install(),
244 * because we need to register the irq via omapdss. Once omapdss and
245 * omapdrm are merged together we can assign the dispc hwmod data to
246 * ourselves and drop these and just use drm_irq_{install,uninstall}()
249 int omap_drm_irq_install(struct drm_device
*dev
)
253 mutex_lock(&dev
->struct_mutex
);
255 if (dev
->irq_enabled
) {
256 mutex_unlock(&dev
->struct_mutex
);
259 dev
->irq_enabled
= 1;
260 mutex_unlock(&dev
->struct_mutex
);
262 /* Before installing handler */
263 if (dev
->driver
->irq_preinstall
)
264 dev
->driver
->irq_preinstall(dev
);
266 ret
= dispc_request_irq(dev
->driver
->irq_handler
, dev
);
269 mutex_lock(&dev
->struct_mutex
);
270 dev
->irq_enabled
= 0;
271 mutex_unlock(&dev
->struct_mutex
);
275 /* After installing handler */
276 if (dev
->driver
->irq_postinstall
)
277 ret
= dev
->driver
->irq_postinstall(dev
);
280 mutex_lock(&dev
->struct_mutex
);
281 dev
->irq_enabled
= 0;
282 mutex_unlock(&dev
->struct_mutex
);
289 int omap_drm_irq_uninstall(struct drm_device
*dev
)
291 unsigned long irqflags
;
294 mutex_lock(&dev
->struct_mutex
);
295 irq_enabled
= dev
->irq_enabled
;
296 dev
->irq_enabled
= 0;
297 mutex_unlock(&dev
->struct_mutex
);
300 * Wake up any waiters so they don't hang.
302 if (dev
->num_crtcs
) {
303 spin_lock_irqsave(&dev
->vbl_lock
, irqflags
);
304 for (i
= 0; i
< dev
->num_crtcs
; i
++) {
305 DRM_WAKEUP(&dev
->vbl_queue
[i
]);
306 dev
->vblank_enabled
[i
] = 0;
307 dev
->last_vblank
[i
] =
308 dev
->driver
->get_vblank_counter(dev
, i
);
310 spin_unlock_irqrestore(&dev
->vbl_lock
, irqflags
);
316 if (dev
->driver
->irq_uninstall
)
317 dev
->driver
->irq_uninstall(dev
);