Merge tag 'drm-intel-next-2012-12-21' of git://people.freedesktop.org/~danvet/drm...
[pandora-kernel.git] / drivers / gpu / drm / i915 / i915_irq.c
index 2220dec..6689a61 100644 (file)
@@ -287,6 +287,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
 
+       /* HPD irq before everything is fully set up. */
+       if (!dev_priv->enable_hotplug_processing)
+               return;
+
        mutex_lock(&mode_config->mutex);
        DRM_DEBUG_KMS("running encoder hotplug functions\n");
 
@@ -300,9 +304,6 @@ static void i915_hotplug_work_func(struct work_struct *work)
        drm_helper_hpd_irq_event(dev);
 }
 
-/* defined intel_pm.c */
-extern spinlock_t mchdev_lock;
-
 static void ironlake_handle_rps_change(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -524,6 +525,20 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
        queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
 
+static void gmbus_irq_handler(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       wake_up_all(&dev_priv->gmbus_wait_queue);
+}
+
+static void dp_aux_irq_handler(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       wake_up_all(&dev_priv->gmbus_wait_queue);
+}
+
 static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -533,7 +548,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
        unsigned long irqflags;
        int pipe;
        u32 pipe_stats[I915_MAX_PIPES];
-       bool blc_event;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -590,8 +604,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
-               if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
-                       blc_event = true;
+               if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
+                       gmbus_irq_handler(dev);
 
                if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
                        gen6_queue_rps_work(dev_priv, pm_iir);
@@ -618,8 +632,11 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
                                 (pch_iir & SDE_AUDIO_POWER_MASK) >>
                                 SDE_AUDIO_POWER_SHIFT);
 
+       if (pch_iir & SDE_AUX_MASK)
+               dp_aux_irq_handler(dev);
+
        if (pch_iir & SDE_GMBUS)
-               DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
+               gmbus_irq_handler(dev);
 
        if (pch_iir & SDE_AUDIO_HDCP_MASK)
                DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
@@ -662,10 +679,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
                                 SDE_AUDIO_POWER_SHIFT_CPT);
 
        if (pch_iir & SDE_AUX_MASK_CPT)
-               DRM_DEBUG_DRIVER("AUX channel interrupt\n");
+               dp_aux_irq_handler(dev);
 
        if (pch_iir & SDE_GMBUS_CPT)
-               DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n");
+               gmbus_irq_handler(dev);
 
        if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
                DRM_DEBUG_DRIVER("Audio CP request interrupt\n");
@@ -703,6 +720,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
 
        de_iir = I915_READ(DEIIR);
        if (de_iir) {
+               if (de_iir & DE_AUX_CHANNEL_A_IVB)
+                       dp_aux_irq_handler(dev);
+
                if (de_iir & DE_GSE_IVB)
                        intel_opregion_gse_intr(dev);
 
@@ -758,7 +778,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
-       u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
+       u32 de_iir, gt_iir, de_ier, pm_iir;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -769,11 +789,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 
        de_iir = I915_READ(DEIIR);
        gt_iir = I915_READ(GTIIR);
-       pch_iir = I915_READ(SDEIIR);
        pm_iir = I915_READ(GEN6_PMIIR);
 
-       if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
-           (!IS_GEN6(dev) || pm_iir == 0))
+       if (de_iir == 0 && gt_iir == 0 && (!IS_GEN6(dev) || pm_iir == 0))
                goto done;
 
        ret = IRQ_HANDLED;
@@ -783,6 +801,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        else
                snb_gt_irq_handler(dev, dev_priv, gt_iir);
 
+       if (de_iir & DE_AUX_CHANNEL_A)
+               dp_aux_irq_handler(dev);
+
        if (de_iir & DE_GSE)
                intel_opregion_gse_intr(dev);
 
@@ -804,10 +825,15 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 
        /* check event from PCH */
        if (de_iir & DE_PCH_EVENT) {
+               u32 pch_iir = I915_READ(SDEIIR);
+
                if (HAS_PCH_CPT(dev))
                        cpt_irq_handler(dev, pch_iir);
                else
                        ibx_irq_handler(dev, pch_iir);
+
+               /* should clear PCH hotplug event before clear CPU irq */
+               I915_WRITE(SDEIIR, pch_iir);
        }
 
        if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
@@ -816,8 +842,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
                gen6_queue_rps_work(dev_priv, pm_iir);
 
-       /* should clear PCH hotplug event before clear CPU irq */
-       I915_WRITE(SDEIIR, pch_iir);
        I915_WRITE(GTIIR, gt_iir);
        I915_WRITE(DEIIR, de_iir);
        I915_WRITE(GEN6_PMIIR, pm_iir);
@@ -928,6 +952,14 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
                                                     reloc_offset);
                        memcpy_fromio(d, s, PAGE_SIZE);
                        io_mapping_unmap_atomic(s);
+               } else if (src->stolen) {
+                       unsigned long offset;
+
+                       offset = dev_priv->mm.stolen_base;
+                       offset += src->stolen->start;
+                       offset += i << PAGE_SHIFT;
+
+                       memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);
                } else {
                        struct page *page;
                        void *s;
@@ -1074,6 +1106,8 @@ static void i915_gem_record_fences(struct drm_device *dev,
                        error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
                break;
 
+       default:
+               BUG();
        }
 }
 
@@ -1854,7 +1888,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        /* enable kind of interrupts always enabled */
        u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
-                          DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
+                          DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
+                          DE_AUX_CHANNEL_A;
        u32 render_irqs;
        u32 hotplug_mask;
 
@@ -1888,12 +1923,15 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
                                SDE_PORTB_HOTPLUG_CPT |
                                SDE_PORTC_HOTPLUG_CPT |
-                               SDE_PORTD_HOTPLUG_CPT);
+                               SDE_PORTD_HOTPLUG_CPT |
+                               SDE_GMBUS_CPT |
+                               SDE_AUX_MASK_CPT);
        } else {
                hotplug_mask = (SDE_CRT_HOTPLUG |
                                SDE_PORTB_HOTPLUG |
                                SDE_PORTC_HOTPLUG |
                                SDE_PORTD_HOTPLUG |
+                               SDE_GMBUS |
                                SDE_AUX_MASK);
        }
 
@@ -1924,7 +1962,8 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
                DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB |
                DE_PLANEC_FLIP_DONE_IVB |
                DE_PLANEB_FLIP_DONE_IVB |
-               DE_PLANEA_FLIP_DONE_IVB;
+               DE_PLANEA_FLIP_DONE_IVB |
+               DE_AUX_CHANNEL_A_IVB;
        u32 render_irqs;
        u32 hotplug_mask;
 
@@ -1953,7 +1992,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
        hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
                        SDE_PORTB_HOTPLUG_CPT |
                        SDE_PORTC_HOTPLUG_CPT |
-                       SDE_PORTD_HOTPLUG_CPT);
+                       SDE_PORTD_HOTPLUG_CPT |
+                       SDE_GMBUS_CPT |
+                       SDE_AUX_MASK_CPT);
        dev_priv->pch_irq_mask = ~hotplug_mask;
 
        I915_WRITE(SDEIIR, I915_READ(SDEIIR));
@@ -1970,7 +2011,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
-       u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
        u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
        u32 render_irqs;
        u16 msid;
@@ -1999,6 +2039,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        msid |= (1<<14);
        pci_write_config_word(dev_priv->dev->pdev, 0x98, msid);
 
+       I915_WRITE(PORT_HOTPLUG_EN, 0);
+       POSTING_READ(PORT_HOTPLUG_EN);
+
        I915_WRITE(VLV_IMR, dev_priv->irq_mask);
        I915_WRITE(VLV_IER, enable_mask);
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -2007,6 +2050,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 
        i915_enable_pipestat(dev_priv, 0, pipestat_enable);
+       i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
        i915_enable_pipestat(dev_priv, 1, pipestat_enable);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -2027,6 +2071,15 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 #endif
 
        I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
+
+       return 0;
+}
+
+static void valleyview_hpd_irq_setup(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+
        /* Note HDMI and DP share bits */
        if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
                hotplug_en |= HDMIB_HOTPLUG_INT_EN;
@@ -2044,8 +2097,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        }
 
        I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-
-       return 0;
 }
 
 static void valleyview_irq_uninstall(struct drm_device *dev)
@@ -2275,6 +2326,9 @@ static int i915_irq_postinstall(struct drm_device *dev)
                I915_USER_INTERRUPT;
 
        if (I915_HAS_HOTPLUG(dev)) {
+               I915_WRITE(PORT_HOTPLUG_EN, 0);
+               POSTING_READ(PORT_HOTPLUG_EN);
+
                /* Enable in IER... */
                enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
                /* and unmask in IMR */
@@ -2285,8 +2339,18 @@ static int i915_irq_postinstall(struct drm_device *dev)
        I915_WRITE(IER, enable_mask);
        POSTING_READ(IER);
 
+       intel_opregion_enable_asle(dev);
+
+       return 0;
+}
+
+static void i915_hpd_irq_setup(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 hotplug_en;
+
        if (I915_HAS_HOTPLUG(dev)) {
-               u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+               hotplug_en = I915_READ(PORT_HOTPLUG_EN);
 
                if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
                        hotplug_en |= HDMIB_HOTPLUG_INT_EN;
@@ -2307,10 +2371,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
 
                I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
        }
-
-       intel_opregion_enable_asle(dev);
-
-       return 0;
 }
 
 static irqreturn_t i915_irq_handler(int irq, void *arg)
@@ -2470,7 +2530,6 @@ static void i965_irq_preinstall(struct drm_device * dev)
 static int i965_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 hotplug_en;
        u32 enable_mask;
        u32 error_mask;
 
@@ -2491,6 +2550,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
 
        dev_priv->pipestat[0] = 0;
        dev_priv->pipestat[1] = 0;
+       i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
 
        /*
         * Enable some error detection, note the instruction error mask
@@ -2511,6 +2571,19 @@ static int i965_irq_postinstall(struct drm_device *dev)
        I915_WRITE(IER, enable_mask);
        POSTING_READ(IER);
 
+       I915_WRITE(PORT_HOTPLUG_EN, 0);
+       POSTING_READ(PORT_HOTPLUG_EN);
+
+       intel_opregion_enable_asle(dev);
+
+       return 0;
+}
+
+static void i965_hpd_irq_setup(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 hotplug_en;
+
        /* Note HDMI and DP share hotplug bits */
        hotplug_en = 0;
        if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
@@ -2545,10 +2618,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
        /* Ignore TV since it's buggy */
 
        I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-
-       intel_opregion_enable_asle(dev);
-
-       return 0;
 }
 
 static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -2644,6 +2713,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
 
+               if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
+                       gmbus_irq_handler(dev);
+
                /* With MSI, interrupts are only generated when iir
                 * transitions from zero to nonzero.  If another bit got
                 * set while we were handling the existing iir bits, then
@@ -2699,6 +2771,11 @@ void intel_irq_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
        INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
 
+       setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
+                   (unsigned long) dev);
+
+       pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
        if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
@@ -2719,7 +2796,8 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->irq_uninstall = valleyview_irq_uninstall;
                dev->driver->enable_vblank = valleyview_enable_vblank;
                dev->driver->disable_vblank = valleyview_disable_vblank;
-       } else if (IS_IVYBRIDGE(dev)) {
+               dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup;
+       } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
                /* Share pre & uninstall handlers with ILK/SNB */
                dev->driver->irq_handler = ivybridge_irq_handler;
                dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2727,14 +2805,6 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->irq_uninstall = ironlake_irq_uninstall;
                dev->driver->enable_vblank = ivybridge_enable_vblank;
                dev->driver->disable_vblank = ivybridge_disable_vblank;
-       } else if (IS_HASWELL(dev)) {
-               /* Share interrupts handling with IVB */
-               dev->driver->irq_handler = ivybridge_irq_handler;
-               dev->driver->irq_preinstall = ironlake_irq_preinstall;
-               dev->driver->irq_postinstall = ivybridge_irq_postinstall;
-               dev->driver->irq_uninstall = ironlake_irq_uninstall;
-               dev->driver->enable_vblank = ivybridge_enable_vblank;
-               dev->driver->disable_vblank = ivybridge_disable_vblank;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev->driver->irq_handler = ironlake_irq_handler;
                dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2753,13 +2823,23 @@ void intel_irq_init(struct drm_device *dev)
                        dev->driver->irq_postinstall = i915_irq_postinstall;
                        dev->driver->irq_uninstall = i915_irq_uninstall;
                        dev->driver->irq_handler = i915_irq_handler;
+                       dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
                } else {
                        dev->driver->irq_preinstall = i965_irq_preinstall;
                        dev->driver->irq_postinstall = i965_irq_postinstall;
                        dev->driver->irq_uninstall = i965_irq_uninstall;
                        dev->driver->irq_handler = i965_irq_handler;
+                       dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup;
                }
                dev->driver->enable_vblank = i915_enable_vblank;
                dev->driver->disable_vblank = i915_disable_vblank;
        }
 }
+
+void intel_hpd_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->display.hpd_irq_setup)
+               dev_priv->display.hpd_irq_setup(dev);
+}