1 /* 2 * drivers/gpu/drm/omapdrm/omap_irq.c 3 * 4 * Copyright (C) 2012 Texas Instruments 5 * Author: Rob Clark <rob.clark@linaro.org> 6 * 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. 10 * 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 14 * more details. 15 * 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/>. 18 */ 19 20 #include "omap_drv.h" 21 22 static DEFINE_SPINLOCK(list_lock); 23 24 static void omap_irq_error_handler(struct omap_drm_irq *irq, 25 uint32_t irqstatus) 26 { 27 DRM_ERROR("errors: %08x\n", irqstatus); 28 } 29 30 /* call with list_lock and dispc runtime held */ 31 static void omap_irq_update(struct drm_device *dev) 32 { 33 struct omap_drm_private *priv = dev->dev_private; 34 struct omap_drm_irq *irq; 35 uint32_t irqmask = priv->vblank_mask; 36 37 assert_spin_locked(&list_lock); 38 39 list_for_each_entry(irq, &priv->irq_list, node) 40 irqmask |= irq->irqmask; 41 42 DBG("irqmask=%08x", irqmask); 43 44 dispc_write_irqenable(irqmask); 45 dispc_read_irqenable(); /* flush posted write */ 46 } 47 48 void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) 49 { 50 struct omap_drm_private *priv = dev->dev_private; 51 unsigned long flags; 52 53 spin_lock_irqsave(&list_lock, flags); 54 55 if (!WARN_ON(irq->registered)) { 56 irq->registered = true; 57 list_add(&irq->node, &priv->irq_list); 58 omap_irq_update(dev); 59 } 60 61 spin_unlock_irqrestore(&list_lock, flags); 62 } 63 64 void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) 65 { 66 dispc_runtime_get(); 67 68 __omap_irq_register(dev, irq); 69 70 dispc_runtime_put(); 71 } 72 73 void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) 74 { 75 unsigned long flags; 76 77 spin_lock_irqsave(&list_lock, flags); 78 79 if (!WARN_ON(!irq->registered)) { 80 irq->registered = false; 81 list_del(&irq->node); 82 omap_irq_update(dev); 83 } 84 85 spin_unlock_irqrestore(&list_lock, flags); 86 } 87 88 void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) 89 { 90 dispc_runtime_get(); 91 92 __omap_irq_unregister(dev, irq); 93 94 dispc_runtime_put(); 95 } 96 97 struct omap_irq_wait { 98 struct omap_drm_irq irq; 99 int count; 100 }; 101 102 static DECLARE_WAIT_QUEUE_HEAD(wait_event); 103 104 static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 105 { 106 struct omap_irq_wait *wait = 107 container_of(irq, struct omap_irq_wait, irq); 108 wait->count--; 109 wake_up_all(&wait_event); 110 } 111 112 struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, 113 uint32_t irqmask, int count) 114 { 115 struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); 116 wait->irq.irq = wait_irq; 117 wait->irq.irqmask = irqmask; 118 wait->count = count; 119 omap_irq_register(dev, &wait->irq); 120 return wait; 121 } 122 123 int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, 124 unsigned long timeout) 125 { 126 int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout); 127 omap_irq_unregister(dev, &wait->irq); 128 kfree(wait); 129 if (ret == 0) 130 return -1; 131 return 0; 132 } 133 134 /** 135 * enable_vblank - enable vblank interrupt events 136 * @dev: DRM device 137 * @crtc: which irq to enable 138 * 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. 142 * 143 * RETURNS 144 * Zero on success, appropriate errno if the given @crtc's vblank 145 * interrupt cannot be enabled. 146 */ 147 int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) 148 { 149 struct omap_drm_private *priv = dev->dev_private; 150 struct drm_crtc *crtc = priv->crtcs[crtc_id]; 151 unsigned long flags; 152 153 DBG("dev=%p, crtc=%d", dev, crtc_id); 154 155 dispc_runtime_get(); 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); 160 dispc_runtime_put(); 161 162 return 0; 163 } 164 165 /** 166 * disable_vblank - disable vblank interrupt events 167 * @dev: DRM device 168 * @crtc: which irq to enable 169 * 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. 173 */ 174 void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id) 175 { 176 struct omap_drm_private *priv = dev->dev_private; 177 struct drm_crtc *crtc = priv->crtcs[crtc_id]; 178 unsigned long flags; 179 180 DBG("dev=%p, crtc=%d", dev, crtc_id); 181 182 dispc_runtime_get(); 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); 187 dispc_runtime_put(); 188 } 189 190 irqreturn_t omap_irq_handler(int irq, void *arg) 191 { 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; 195 unsigned long flags; 196 unsigned int id; 197 u32 irqstatus; 198 199 irqstatus = dispc_read_irqstatus(); 200 dispc_clear_irqstatus(irqstatus); 201 dispc_read_irqstatus(); /* flush posted write */ 202 203 VERB("irqs: %08x", irqstatus); 204 205 for (id = 0; id < priv->num_crtcs; id++) { 206 struct drm_crtc *crtc = priv->crtcs[id]; 207 208 if (irqstatus & pipe2vbl(crtc)) 209 drm_handle_vblank(dev, id); 210 } 211 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); 218 } 219 } 220 spin_unlock_irqrestore(&list_lock, flags); 221 222 return IRQ_HANDLED; 223 } 224 225 void omap_irq_preinstall(struct drm_device *dev) 226 { 227 DBG("dev=%p", dev); 228 dispc_runtime_get(); 229 dispc_clear_irqstatus(0xffffffff); 230 dispc_runtime_put(); 231 } 232 233 int omap_irq_postinstall(struct drm_device *dev) 234 { 235 struct omap_drm_private *priv = dev->dev_private; 236 struct omap_drm_irq *error_handler = &priv->error_handler; 237 238 DBG("dev=%p", dev); 239 240 INIT_LIST_HEAD(&priv->irq_list); 241 242 error_handler->irq = omap_irq_error_handler; 243 error_handler->irqmask = DISPC_IRQ_OCP_ERR; 244 245 /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think 246 * we just need to ignore it while enabling tv-out 247 */ 248 error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; 249 250 omap_irq_register(dev, error_handler); 251 252 return 0; 253 } 254 255 void omap_irq_uninstall(struct drm_device *dev) 256 { 257 DBG("dev=%p", dev); 258 // TODO prolly need to call drm_irq_uninstall() somewhere too 259 } 260 261 /* 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}() 266 */ 267 268 int omap_drm_irq_install(struct drm_device *dev) 269 { 270 int ret; 271 272 mutex_lock(&dev->struct_mutex); 273 274 if (dev->irq_enabled) { 275 mutex_unlock(&dev->struct_mutex); 276 return -EBUSY; 277 } 278 dev->irq_enabled = true; 279 mutex_unlock(&dev->struct_mutex); 280 281 /* Before installing handler */ 282 if (dev->driver->irq_preinstall) 283 dev->driver->irq_preinstall(dev); 284 285 ret = dispc_request_irq(dev->driver->irq_handler, dev); 286 287 if (ret < 0) { 288 mutex_lock(&dev->struct_mutex); 289 dev->irq_enabled = false; 290 mutex_unlock(&dev->struct_mutex); 291 return ret; 292 } 293 294 /* After installing handler */ 295 if (dev->driver->irq_postinstall) 296 ret = dev->driver->irq_postinstall(dev); 297 298 if (ret < 0) { 299 mutex_lock(&dev->struct_mutex); 300 dev->irq_enabled = false; 301 mutex_unlock(&dev->struct_mutex); 302 dispc_free_irq(dev); 303 } 304 305 return ret; 306 } 307 308 int omap_drm_irq_uninstall(struct drm_device *dev) 309 { 310 unsigned long irqflags; 311 bool irq_enabled; 312 int i; 313 314 mutex_lock(&dev->struct_mutex); 315 irq_enabled = dev->irq_enabled; 316 dev->irq_enabled = false; 317 mutex_unlock(&dev->struct_mutex); 318 319 /* 320 * Wake up any waiters so they don't hang. 321 */ 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); 329 } 330 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 331 } 332 333 if (!irq_enabled) 334 return -EINVAL; 335 336 if (dev->driver->irq_uninstall) 337 dev->driver->irq_uninstall(dev); 338 339 dispc_free_irq(dev); 340 341 return 0; 342 } 343