1c0e09200SDave Airlie /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- 2c0e09200SDave Airlie */ 3c0e09200SDave Airlie /* 4c0e09200SDave Airlie * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 5c0e09200SDave Airlie * All Rights Reserved. 6c0e09200SDave Airlie * 7c0e09200SDave Airlie * Permission is hereby granted, free of charge, to any person obtaining a 8c0e09200SDave Airlie * copy of this software and associated documentation files (the 9c0e09200SDave Airlie * "Software"), to deal in the Software without restriction, including 10c0e09200SDave Airlie * without limitation the rights to use, copy, modify, merge, publish, 11c0e09200SDave Airlie * distribute, sub license, and/or sell copies of the Software, and to 12c0e09200SDave Airlie * permit persons to whom the Software is furnished to do so, subject to 13c0e09200SDave Airlie * the following conditions: 14c0e09200SDave Airlie * 15c0e09200SDave Airlie * The above copyright notice and this permission notice (including the 16c0e09200SDave Airlie * next paragraph) shall be included in all copies or substantial portions 17c0e09200SDave Airlie * of the Software. 18c0e09200SDave Airlie * 19c0e09200SDave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20c0e09200SDave Airlie * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21c0e09200SDave Airlie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22c0e09200SDave Airlie * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 23c0e09200SDave Airlie * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24c0e09200SDave Airlie * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25c0e09200SDave Airlie * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26c0e09200SDave Airlie * 27c0e09200SDave Airlie */ 28c0e09200SDave Airlie 29c0e09200SDave Airlie #include "drmP.h" 30c0e09200SDave Airlie #include "drm.h" 31c0e09200SDave Airlie #include "i915_drm.h" 32c0e09200SDave Airlie #include "i915_drv.h" 33c0e09200SDave Airlie 34c0e09200SDave Airlie #define MAX_NOPID ((u32)~0) 35c0e09200SDave Airlie 36*7c463586SKeith Packard /** 37*7c463586SKeith Packard * Interrupts that are always left unmasked. 38*7c463586SKeith Packard * 39*7c463586SKeith Packard * Since pipe events are edge-triggered from the PIPESTAT register to IIR, 40*7c463586SKeith Packard * we leave them always unmasked in IMR and then control enabling them through 41*7c463586SKeith Packard * PIPESTAT alone. 42*7c463586SKeith Packard */ 43*7c463586SKeith Packard #define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \ 440a3e67a4SJesse Barnes I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ 458ee1c3dbSMatthew Garrett I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) 46ed4cb414SEric Anholt 47*7c463586SKeith Packard /** Interrupts that we mask and unmask at runtime. */ 48*7c463586SKeith Packard #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) 49*7c463586SKeith Packard 50*7c463586SKeith Packard /** These are all of the interrupts used by the driver */ 51*7c463586SKeith Packard #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ 52*7c463586SKeith Packard I915_INTERRUPT_ENABLE_VAR) 53*7c463586SKeith Packard 548ee1c3dbSMatthew Garrett void 55ed4cb414SEric Anholt i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) 56ed4cb414SEric Anholt { 57ed4cb414SEric Anholt if ((dev_priv->irq_mask_reg & mask) != 0) { 58ed4cb414SEric Anholt dev_priv->irq_mask_reg &= ~mask; 59ed4cb414SEric Anholt I915_WRITE(IMR, dev_priv->irq_mask_reg); 60ed4cb414SEric Anholt (void) I915_READ(IMR); 61ed4cb414SEric Anholt } 62ed4cb414SEric Anholt } 63ed4cb414SEric Anholt 64ed4cb414SEric Anholt static inline void 65ed4cb414SEric Anholt i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) 66ed4cb414SEric Anholt { 67ed4cb414SEric Anholt if ((dev_priv->irq_mask_reg & mask) != mask) { 68ed4cb414SEric Anholt dev_priv->irq_mask_reg |= mask; 69ed4cb414SEric Anholt I915_WRITE(IMR, dev_priv->irq_mask_reg); 70ed4cb414SEric Anholt (void) I915_READ(IMR); 71ed4cb414SEric Anholt } 72ed4cb414SEric Anholt } 73ed4cb414SEric Anholt 74*7c463586SKeith Packard static inline u32 75*7c463586SKeith Packard i915_pipestat(int pipe) 76*7c463586SKeith Packard { 77*7c463586SKeith Packard if (pipe == 0) 78*7c463586SKeith Packard return PIPEASTAT; 79*7c463586SKeith Packard if (pipe == 1) 80*7c463586SKeith Packard return PIPEBSTAT; 81*7c463586SKeith Packard BUG_ON(1); 82*7c463586SKeith Packard } 83*7c463586SKeith Packard 84*7c463586SKeith Packard void 85*7c463586SKeith Packard i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) 86*7c463586SKeith Packard { 87*7c463586SKeith Packard if ((dev_priv->pipestat[pipe] & mask) != mask) { 88*7c463586SKeith Packard u32 reg = i915_pipestat(pipe); 89*7c463586SKeith Packard 90*7c463586SKeith Packard dev_priv->pipestat[pipe] |= mask; 91*7c463586SKeith Packard /* Enable the interrupt, clear any pending status */ 92*7c463586SKeith Packard I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); 93*7c463586SKeith Packard (void) I915_READ(reg); 94*7c463586SKeith Packard } 95*7c463586SKeith Packard } 96*7c463586SKeith Packard 97*7c463586SKeith Packard void 98*7c463586SKeith Packard i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) 99*7c463586SKeith Packard { 100*7c463586SKeith Packard if ((dev_priv->pipestat[pipe] & mask) != 0) { 101*7c463586SKeith Packard u32 reg = i915_pipestat(pipe); 102*7c463586SKeith Packard 103*7c463586SKeith Packard dev_priv->pipestat[pipe] &= ~mask; 104*7c463586SKeith Packard I915_WRITE(reg, dev_priv->pipestat[pipe]); 105*7c463586SKeith Packard (void) I915_READ(reg); 106*7c463586SKeith Packard } 107*7c463586SKeith Packard } 108*7c463586SKeith Packard 109c0e09200SDave Airlie /** 1100a3e67a4SJesse Barnes * i915_pipe_enabled - check if a pipe is enabled 1110a3e67a4SJesse Barnes * @dev: DRM device 1120a3e67a4SJesse Barnes * @pipe: pipe to check 1130a3e67a4SJesse Barnes * 1140a3e67a4SJesse Barnes * Reading certain registers when the pipe is disabled can hang the chip. 1150a3e67a4SJesse Barnes * Use this routine to make sure the PLL is running and the pipe is active 1160a3e67a4SJesse Barnes * before reading such registers if unsure. 1170a3e67a4SJesse Barnes */ 1180a3e67a4SJesse Barnes static int 1190a3e67a4SJesse Barnes i915_pipe_enabled(struct drm_device *dev, int pipe) 1200a3e67a4SJesse Barnes { 1210a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1220a3e67a4SJesse Barnes unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; 1230a3e67a4SJesse Barnes 1240a3e67a4SJesse Barnes if (I915_READ(pipeconf) & PIPEACONF_ENABLE) 1250a3e67a4SJesse Barnes return 1; 1260a3e67a4SJesse Barnes 1270a3e67a4SJesse Barnes return 0; 1280a3e67a4SJesse Barnes } 1290a3e67a4SJesse Barnes 13042f52ef8SKeith Packard /* Called from drm generic code, passed a 'crtc', which 13142f52ef8SKeith Packard * we use as a pipe index 13242f52ef8SKeith Packard */ 13342f52ef8SKeith Packard u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) 1340a3e67a4SJesse Barnes { 1350a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1360a3e67a4SJesse Barnes unsigned long high_frame; 1370a3e67a4SJesse Barnes unsigned long low_frame; 1380a3e67a4SJesse Barnes u32 high1, high2, low, count; 1390a3e67a4SJesse Barnes 1400a3e67a4SJesse Barnes high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; 1410a3e67a4SJesse Barnes low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; 1420a3e67a4SJesse Barnes 1430a3e67a4SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) { 1440a3e67a4SJesse Barnes DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); 1450a3e67a4SJesse Barnes return 0; 1460a3e67a4SJesse Barnes } 1470a3e67a4SJesse Barnes 1480a3e67a4SJesse Barnes /* 1490a3e67a4SJesse Barnes * High & low register fields aren't synchronized, so make sure 1500a3e67a4SJesse Barnes * we get a low value that's stable across two reads of the high 1510a3e67a4SJesse Barnes * register. 1520a3e67a4SJesse Barnes */ 1530a3e67a4SJesse Barnes do { 1540a3e67a4SJesse Barnes high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> 1550a3e67a4SJesse Barnes PIPE_FRAME_HIGH_SHIFT); 1560a3e67a4SJesse Barnes low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> 1570a3e67a4SJesse Barnes PIPE_FRAME_LOW_SHIFT); 1580a3e67a4SJesse Barnes high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> 1590a3e67a4SJesse Barnes PIPE_FRAME_HIGH_SHIFT); 1600a3e67a4SJesse Barnes } while (high1 != high2); 1610a3e67a4SJesse Barnes 1620a3e67a4SJesse Barnes count = (high1 << 8) | low; 1630a3e67a4SJesse Barnes 1640a3e67a4SJesse Barnes return count; 1650a3e67a4SJesse Barnes } 1660a3e67a4SJesse Barnes 167c0e09200SDave Airlie irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 168c0e09200SDave Airlie { 169c0e09200SDave Airlie struct drm_device *dev = (struct drm_device *) arg; 170c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 171ed4cb414SEric Anholt u32 iir; 172*7c463586SKeith Packard u32 pipea_stats = 0, pipeb_stats = 0; 1730a3e67a4SJesse Barnes int vblank = 0; 174*7c463586SKeith Packard unsigned long irqflags; 175c0e09200SDave Airlie 176*7c463586SKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 177630681d9SEric Anholt atomic_inc(&dev_priv->irq_received); 178630681d9SEric Anholt 179ed4cb414SEric Anholt if (dev->pdev->msi_enabled) 180ed4cb414SEric Anholt I915_WRITE(IMR, ~0); 181ed4cb414SEric Anholt iir = I915_READ(IIR); 182c0e09200SDave Airlie 183ed4cb414SEric Anholt if (iir == 0) { 184ed4cb414SEric Anholt if (dev->pdev->msi_enabled) { 185ed4cb414SEric Anholt I915_WRITE(IMR, dev_priv->irq_mask_reg); 186ed4cb414SEric Anholt (void) I915_READ(IMR); 187ed4cb414SEric Anholt } 188*7c463586SKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 189c0e09200SDave Airlie return IRQ_NONE; 190ed4cb414SEric Anholt } 191c0e09200SDave Airlie 1920a3e67a4SJesse Barnes /* 193*7c463586SKeith Packard * Clear the PIPE(A|B)STAT regs before the IIR 1940a3e67a4SJesse Barnes */ 1950a3e67a4SJesse Barnes if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { 1960a3e67a4SJesse Barnes pipea_stats = I915_READ(PIPEASTAT); 1978ee1c3dbSMatthew Garrett I915_WRITE(PIPEASTAT, pipea_stats); 1980a3e67a4SJesse Barnes } 199*7c463586SKeith Packard 2000a3e67a4SJesse Barnes if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { 2010a3e67a4SJesse Barnes pipeb_stats = I915_READ(PIPEBSTAT); 2020a3e67a4SJesse Barnes I915_WRITE(PIPEBSTAT, pipeb_stats); 203c0e09200SDave Airlie } 204c0e09200SDave Airlie 205673a394bSEric Anholt I915_WRITE(IIR, iir); 206673a394bSEric Anholt if (dev->pdev->msi_enabled) 207673a394bSEric Anholt I915_WRITE(IMR, dev_priv->irq_mask_reg); 208673a394bSEric Anholt (void) I915_READ(IIR); /* Flush posted writes */ 2098ee1c3dbSMatthew Garrett 210*7c463586SKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 211*7c463586SKeith Packard 212c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 213c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_dispatch = 214c99b058fSKristian Høgsberg READ_BREADCRUMB(dev_priv); 2150a3e67a4SJesse Barnes 216673a394bSEric Anholt if (iir & I915_USER_INTERRUPT) { 217673a394bSEric Anholt dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); 218673a394bSEric Anholt DRM_WAKEUP(&dev_priv->irq_queue); 219673a394bSEric Anholt } 220673a394bSEric Anholt 221*7c463586SKeith Packard if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) { 222*7c463586SKeith Packard vblank++; 223*7c463586SKeith Packard drm_handle_vblank(dev, 0); 224*7c463586SKeith Packard } 225*7c463586SKeith Packard 226*7c463586SKeith Packard if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) { 227*7c463586SKeith Packard vblank++; 228*7c463586SKeith Packard drm_handle_vblank(dev, 1); 229*7c463586SKeith Packard } 230*7c463586SKeith Packard 231*7c463586SKeith Packard if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) || 232*7c463586SKeith Packard (iir & I915_ASLE_INTERRUPT)) 233673a394bSEric Anholt opregion_asle_intr(dev); 2340a3e67a4SJesse Barnes 235c0e09200SDave Airlie return IRQ_HANDLED; 236c0e09200SDave Airlie } 237c0e09200SDave Airlie 238c0e09200SDave Airlie static int i915_emit_irq(struct drm_device * dev) 239c0e09200SDave Airlie { 240c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 241c0e09200SDave Airlie RING_LOCALS; 242c0e09200SDave Airlie 243c0e09200SDave Airlie i915_kernel_lost_context(dev); 244c0e09200SDave Airlie 245c0e09200SDave Airlie DRM_DEBUG("\n"); 246c0e09200SDave Airlie 247c99b058fSKristian Høgsberg dev_priv->counter++; 248c0e09200SDave Airlie if (dev_priv->counter > 0x7FFFFFFFUL) 249c99b058fSKristian Høgsberg dev_priv->counter = 1; 250c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 251c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_enqueue = dev_priv->counter; 252c0e09200SDave Airlie 2530baf823aSKeith Packard BEGIN_LP_RING(4); 254585fb111SJesse Barnes OUT_RING(MI_STORE_DWORD_INDEX); 2550baf823aSKeith Packard OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); 256c0e09200SDave Airlie OUT_RING(dev_priv->counter); 257585fb111SJesse Barnes OUT_RING(MI_USER_INTERRUPT); 258c0e09200SDave Airlie ADVANCE_LP_RING(); 259c0e09200SDave Airlie 260c0e09200SDave Airlie return dev_priv->counter; 261c0e09200SDave Airlie } 262c0e09200SDave Airlie 263673a394bSEric Anholt void i915_user_irq_get(struct drm_device *dev) 264ed4cb414SEric Anholt { 265ed4cb414SEric Anholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 266e9d21d7fSKeith Packard unsigned long irqflags; 267ed4cb414SEric Anholt 268e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 269ed4cb414SEric Anholt if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) 270ed4cb414SEric Anholt i915_enable_irq(dev_priv, I915_USER_INTERRUPT); 271e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 272ed4cb414SEric Anholt } 273ed4cb414SEric Anholt 2740a3e67a4SJesse Barnes void i915_user_irq_put(struct drm_device *dev) 275ed4cb414SEric Anholt { 276ed4cb414SEric Anholt drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 277e9d21d7fSKeith Packard unsigned long irqflags; 278ed4cb414SEric Anholt 279e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 280ed4cb414SEric Anholt BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); 281ed4cb414SEric Anholt if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) 282ed4cb414SEric Anholt i915_disable_irq(dev_priv, I915_USER_INTERRUPT); 283e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 284ed4cb414SEric Anholt } 285ed4cb414SEric Anholt 286c0e09200SDave Airlie static int i915_wait_irq(struct drm_device * dev, int irq_nr) 287c0e09200SDave Airlie { 288c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 289c0e09200SDave Airlie int ret = 0; 290c0e09200SDave Airlie 291c0e09200SDave Airlie DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, 292c0e09200SDave Airlie READ_BREADCRUMB(dev_priv)); 293c0e09200SDave Airlie 294ed4cb414SEric Anholt if (READ_BREADCRUMB(dev_priv) >= irq_nr) { 295c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) { 296c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_dispatch = 297c99b058fSKristian Høgsberg READ_BREADCRUMB(dev_priv); 298c99b058fSKristian Høgsberg } 299c0e09200SDave Airlie return 0; 300ed4cb414SEric Anholt } 301c0e09200SDave Airlie 302c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 303c0e09200SDave Airlie dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; 304c0e09200SDave Airlie 305ed4cb414SEric Anholt i915_user_irq_get(dev); 306c0e09200SDave Airlie DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, 307c0e09200SDave Airlie READ_BREADCRUMB(dev_priv) >= irq_nr); 308ed4cb414SEric Anholt i915_user_irq_put(dev); 309c0e09200SDave Airlie 310c0e09200SDave Airlie if (ret == -EBUSY) { 311c0e09200SDave Airlie DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", 312c0e09200SDave Airlie READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); 313c0e09200SDave Airlie } 314c0e09200SDave Airlie 315c99b058fSKristian Høgsberg if (dev_priv->sarea_priv) 316c99b058fSKristian Høgsberg dev_priv->sarea_priv->last_dispatch = 317c99b058fSKristian Høgsberg READ_BREADCRUMB(dev_priv); 318c0e09200SDave Airlie 319c0e09200SDave Airlie return ret; 320c0e09200SDave Airlie } 321c0e09200SDave Airlie 322c0e09200SDave Airlie /* Needs the lock as it touches the ring. 323c0e09200SDave Airlie */ 324c0e09200SDave Airlie int i915_irq_emit(struct drm_device *dev, void *data, 325c0e09200SDave Airlie struct drm_file *file_priv) 326c0e09200SDave Airlie { 327c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 328c0e09200SDave Airlie drm_i915_irq_emit_t *emit = data; 329c0e09200SDave Airlie int result; 330c0e09200SDave Airlie 331546b0974SEric Anholt RING_LOCK_TEST_WITH_RETURN(dev, file_priv); 332c0e09200SDave Airlie 333c0e09200SDave Airlie if (!dev_priv) { 334c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 335c0e09200SDave Airlie return -EINVAL; 336c0e09200SDave Airlie } 337546b0974SEric Anholt mutex_lock(&dev->struct_mutex); 338c0e09200SDave Airlie result = i915_emit_irq(dev); 339546b0974SEric Anholt mutex_unlock(&dev->struct_mutex); 340c0e09200SDave Airlie 341c0e09200SDave Airlie if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { 342c0e09200SDave Airlie DRM_ERROR("copy_to_user\n"); 343c0e09200SDave Airlie return -EFAULT; 344c0e09200SDave Airlie } 345c0e09200SDave Airlie 346c0e09200SDave Airlie return 0; 347c0e09200SDave Airlie } 348c0e09200SDave Airlie 349c0e09200SDave Airlie /* Doesn't need the hardware lock. 350c0e09200SDave Airlie */ 351c0e09200SDave Airlie int i915_irq_wait(struct drm_device *dev, void *data, 352c0e09200SDave Airlie struct drm_file *file_priv) 353c0e09200SDave Airlie { 354c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 355c0e09200SDave Airlie drm_i915_irq_wait_t *irqwait = data; 356c0e09200SDave Airlie 357c0e09200SDave Airlie if (!dev_priv) { 358c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 359c0e09200SDave Airlie return -EINVAL; 360c0e09200SDave Airlie } 361c0e09200SDave Airlie 362c0e09200SDave Airlie return i915_wait_irq(dev, irqwait->irq_seq); 363c0e09200SDave Airlie } 364c0e09200SDave Airlie 36542f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which 36642f52ef8SKeith Packard * we use as a pipe index 36742f52ef8SKeith Packard */ 36842f52ef8SKeith Packard int i915_enable_vblank(struct drm_device *dev, int pipe) 3690a3e67a4SJesse Barnes { 3700a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 371e9d21d7fSKeith Packard unsigned long irqflags; 3720a3e67a4SJesse Barnes 373e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 3740a3e67a4SJesse Barnes if (IS_I965G(dev)) 375*7c463586SKeith Packard i915_enable_pipestat(dev_priv, pipe, 376*7c463586SKeith Packard PIPE_START_VBLANK_INTERRUPT_ENABLE); 3770a3e67a4SJesse Barnes else 378*7c463586SKeith Packard i915_enable_pipestat(dev_priv, pipe, 379*7c463586SKeith Packard PIPE_VBLANK_INTERRUPT_ENABLE); 380e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 3810a3e67a4SJesse Barnes return 0; 3820a3e67a4SJesse Barnes } 3830a3e67a4SJesse Barnes 38442f52ef8SKeith Packard /* Called from drm generic code, passed 'crtc' which 38542f52ef8SKeith Packard * we use as a pipe index 38642f52ef8SKeith Packard */ 38742f52ef8SKeith Packard void i915_disable_vblank(struct drm_device *dev, int pipe) 3880a3e67a4SJesse Barnes { 3890a3e67a4SJesse Barnes drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 390e9d21d7fSKeith Packard unsigned long irqflags; 3910a3e67a4SJesse Barnes 392e9d21d7fSKeith Packard spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); 393*7c463586SKeith Packard i915_disable_pipestat(dev_priv, pipe, 394*7c463586SKeith Packard PIPE_VBLANK_INTERRUPT_ENABLE | 395*7c463586SKeith Packard PIPE_START_VBLANK_INTERRUPT_ENABLE); 396e9d21d7fSKeith Packard spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 3970a3e67a4SJesse Barnes } 3980a3e67a4SJesse Barnes 399c0e09200SDave Airlie /* Set the vblank monitor pipe 400c0e09200SDave Airlie */ 401c0e09200SDave Airlie int i915_vblank_pipe_set(struct drm_device *dev, void *data, 402c0e09200SDave Airlie struct drm_file *file_priv) 403c0e09200SDave Airlie { 404c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 405c0e09200SDave Airlie 406c0e09200SDave Airlie if (!dev_priv) { 407c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 408c0e09200SDave Airlie return -EINVAL; 409c0e09200SDave Airlie } 410c0e09200SDave Airlie 411c0e09200SDave Airlie return 0; 412c0e09200SDave Airlie } 413c0e09200SDave Airlie 414c0e09200SDave Airlie int i915_vblank_pipe_get(struct drm_device *dev, void *data, 415c0e09200SDave Airlie struct drm_file *file_priv) 416c0e09200SDave Airlie { 417c0e09200SDave Airlie drm_i915_private_t *dev_priv = dev->dev_private; 418c0e09200SDave Airlie drm_i915_vblank_pipe_t *pipe = data; 419c0e09200SDave Airlie 420c0e09200SDave Airlie if (!dev_priv) { 421c0e09200SDave Airlie DRM_ERROR("called with no initialization\n"); 422c0e09200SDave Airlie return -EINVAL; 423c0e09200SDave Airlie } 424c0e09200SDave Airlie 4250a3e67a4SJesse Barnes pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; 426c0e09200SDave Airlie 427c0e09200SDave Airlie return 0; 428c0e09200SDave Airlie } 429c0e09200SDave Airlie 430c0e09200SDave Airlie /** 431c0e09200SDave Airlie * Schedule buffer swap at given vertical blank. 432c0e09200SDave Airlie */ 433c0e09200SDave Airlie int i915_vblank_swap(struct drm_device *dev, void *data, 434c0e09200SDave Airlie struct drm_file *file_priv) 435c0e09200SDave Airlie { 436bd95e0a4SEric Anholt /* The delayed swap mechanism was fundamentally racy, and has been 437bd95e0a4SEric Anholt * removed. The model was that the client requested a delayed flip/swap 438bd95e0a4SEric Anholt * from the kernel, then waited for vblank before continuing to perform 439bd95e0a4SEric Anholt * rendering. The problem was that the kernel might wake the client 440bd95e0a4SEric Anholt * up before it dispatched the vblank swap (since the lock has to be 441bd95e0a4SEric Anholt * held while touching the ringbuffer), in which case the client would 442bd95e0a4SEric Anholt * clear and start the next frame before the swap occurred, and 443bd95e0a4SEric Anholt * flicker would occur in addition to likely missing the vblank. 444bd95e0a4SEric Anholt * 445bd95e0a4SEric Anholt * In the absence of this ioctl, userland falls back to a correct path 446bd95e0a4SEric Anholt * of waiting for a vblank, then dispatching the swap on its own. 447bd95e0a4SEric Anholt * Context switching to userland and back is plenty fast enough for 448bd95e0a4SEric Anholt * meeting the requirements of vblank swapping. 4490a3e67a4SJesse Barnes */ 450c0e09200SDave Airlie return -EINVAL; 451c0e09200SDave Airlie } 452c0e09200SDave Airlie 453c0e09200SDave Airlie /* drm_dma.h hooks 454c0e09200SDave Airlie */ 455c0e09200SDave Airlie void i915_driver_irq_preinstall(struct drm_device * dev) 456c0e09200SDave Airlie { 457c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 458c0e09200SDave Airlie 4590a3e67a4SJesse Barnes I915_WRITE(HWSTAM, 0xeffe); 460*7c463586SKeith Packard I915_WRITE(PIPEASTAT, 0); 461*7c463586SKeith Packard I915_WRITE(PIPEBSTAT, 0); 4620a3e67a4SJesse Barnes I915_WRITE(IMR, 0xffffffff); 463ed4cb414SEric Anholt I915_WRITE(IER, 0x0); 464*7c463586SKeith Packard (void) I915_READ(IER); 465c0e09200SDave Airlie } 466c0e09200SDave Airlie 4670a3e67a4SJesse Barnes int i915_driver_irq_postinstall(struct drm_device *dev) 468c0e09200SDave Airlie { 469c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 4700a3e67a4SJesse Barnes int ret, num_pipes = 2; 471c0e09200SDave Airlie 4720a3e67a4SJesse Barnes ret = drm_vblank_init(dev, num_pipes); 4730a3e67a4SJesse Barnes if (ret) 4740a3e67a4SJesse Barnes return ret; 4750a3e67a4SJesse Barnes 4760a3e67a4SJesse Barnes dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; 477ed4cb414SEric Anholt 4780a3e67a4SJesse Barnes dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ 4790a3e67a4SJesse Barnes 480*7c463586SKeith Packard /* Unmask the interrupts that we always want on. */ 481*7c463586SKeith Packard dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; 4828ee1c3dbSMatthew Garrett 483*7c463586SKeith Packard dev_priv->pipestat[0] = 0; 484*7c463586SKeith Packard dev_priv->pipestat[1] = 0; 485*7c463586SKeith Packard 486*7c463586SKeith Packard /* Disable pipe interrupt enables, clear pending pipe status */ 487*7c463586SKeith Packard I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); 488*7c463586SKeith Packard I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); 489*7c463586SKeith Packard /* Clear pending interrupt status */ 490*7c463586SKeith Packard I915_WRITE(IIR, I915_READ(IIR)); 491*7c463586SKeith Packard 492ed4cb414SEric Anholt I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); 493*7c463586SKeith Packard I915_WRITE(IMR, dev_priv->irq_mask_reg); 494ed4cb414SEric Anholt (void) I915_READ(IER); 495ed4cb414SEric Anholt 4968ee1c3dbSMatthew Garrett opregion_enable_asle(dev); 497c0e09200SDave Airlie DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); 4980a3e67a4SJesse Barnes 4990a3e67a4SJesse Barnes return 0; 500c0e09200SDave Airlie } 501c0e09200SDave Airlie 502c0e09200SDave Airlie void i915_driver_irq_uninstall(struct drm_device * dev) 503c0e09200SDave Airlie { 504c0e09200SDave Airlie drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 505c0e09200SDave Airlie 506c0e09200SDave Airlie if (!dev_priv) 507c0e09200SDave Airlie return; 508c0e09200SDave Airlie 5090a3e67a4SJesse Barnes dev_priv->vblank_pipe = 0; 5100a3e67a4SJesse Barnes 5110a3e67a4SJesse Barnes I915_WRITE(HWSTAM, 0xffffffff); 512*7c463586SKeith Packard I915_WRITE(PIPEASTAT, 0); 513*7c463586SKeith Packard I915_WRITE(PIPEBSTAT, 0); 5140a3e67a4SJesse Barnes I915_WRITE(IMR, 0xffffffff); 515ed4cb414SEric Anholt I915_WRITE(IER, 0x0); 516c0e09200SDave Airlie 517*7c463586SKeith Packard I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); 518*7c463586SKeith Packard I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); 519*7c463586SKeith Packard I915_WRITE(IIR, I915_READ(IIR)); 520c0e09200SDave Airlie } 521