On Wed, Apr 09, 2014 at 01:28:08PM +0300, ville.syrj...@linux.intel.com wrote:
> From: Daniel Vetter <daniel.vet...@ffwll.ch>
> 
> CHV has the Gen8 master interrupt register, as well as Gen8
> GT/PCU interrupt registers.
> 
> The display block is based on VLV, with the main difference
> of adding pipe C.
> 
> FIXME: Lot of this is copy pasted from either VLV or BDW. We should
> probably refactor a bit to share the code better.
> 
> v2: Rewrite the order of operations to make more sense
>     Don't bail out if MASTER_CTL register doesn't show an interrupt,
>     as display interrupts aren't reported there.
> 
> v3: Rebase on top of Egbert Eich's hpd irq handling rework by using
> the relevant port hotplug logic like for vlv.
> 
> v4: Rebase on top of Ben's gt irq #define refactoring.
> 
> v5: Squash in gen8_gt_irq_handler refactoring from Zhao Yakui
> <yakui.z...@intel.com>
> 
> v6: Adapt to upstream changes, dev_priv->irq_received is gone.
> 
> v7: Enable 3 the commented-out 3 pipe support.
> 
> v8: Grab irq_lock around i915_enable_pipestat()
> 
> Signed-off-by: Ville Syrjälä <ville.syrj...@linux.intel.com> (v2)
> Signed-off-by: Daniel Vetter <daniel.vet...@ffwll.ch>

Internal has a rebased version of this one here. Can you please fish it
out of there?
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_irq.c | 249 
> +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 248 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 407742f..1581b3d 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1715,6 +1715,95 @@ out:
>       return ret;
>  }
>  
> +static irqreturn_t cherryview_irq_handler(int irq, void *arg)
> +{
> +     struct drm_device *dev = (struct drm_device *) arg;
> +     drm_i915_private_t *dev_priv = dev->dev_private;
> +     u32 master_ctl, iir;
> +     irqreturn_t ret = IRQ_NONE;
> +     unsigned int pipes = 0;
> +
> +     master_ctl = I915_READ(GEN8_MASTER_IRQ);
> +
> +     I915_WRITE(GEN8_MASTER_IRQ, 0);
> +
> +     ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl);
> +
> +     iir = I915_READ(VLV_IIR);
> +
> +     if (iir & (I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | 
> I915_DISPLAY_PIPE_A_EVENT_INTERRUPT))
> +             pipes |= 1 << 0;
> +     if (iir & (I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT | 
> I915_DISPLAY_PIPE_B_EVENT_INTERRUPT))
> +             pipes |= 1 << 1;
> +     if (iir & (I915_DISPLAY_PIPE_C_VBLANK_INTERRUPT | 
> I915_DISPLAY_PIPE_C_EVENT_INTERRUPT))
> +             pipes |= 1 << 2;
> +
> +     if (pipes) {
> +             u32 pipe_stats[I915_MAX_PIPES] = {};
> +             unsigned long irqflags;
> +             int pipe;
> +
> +             spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> +             for_each_pipe(pipe) {
> +                     unsigned int reg;
> +
> +                     if (!(pipes & (1 << pipe)))
> +                             continue;
> +
> +                     reg = PIPESTAT(pipe);
> +                     pipe_stats[pipe] = I915_READ(reg);
> +
> +                     /*
> +                      * Clear the PIPE*STAT regs before the IIR
> +                      */
> +                     if (pipe_stats[pipe] & 0x8000ffff) {
> +                             if (pipe_stats[pipe] & 
> PIPE_FIFO_UNDERRUN_STATUS)
> +                                     DRM_DEBUG_DRIVER("pipe %c underrun\n",
> +                                                      pipe_name(pipe));
> +                             I915_WRITE(reg, pipe_stats[pipe]);
> +                     }
> +             }
> +             spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +
> +             for_each_pipe(pipe) {
> +                     if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
> +                             drm_handle_vblank(dev, pipe);
> +
> +                     if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
> +                             intel_prepare_page_flip(dev, pipe);
> +                             intel_finish_page_flip(dev, pipe);
> +                     }
> +             }
> +
> +             if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
> +                     gmbus_irq_handler(dev);
> +
> +             ret = IRQ_HANDLED;
> +     }
> +
> +     /* Consume port.  Then clear IIR or we'll miss events */
> +     if (iir & I915_DISPLAY_PORT_INTERRUPT) {
> +             u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
> +
> +             I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
> +
> +             DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
> +                              hotplug_status);
> +             if (hotplug_status & HOTPLUG_INT_STATUS_I915)
> +                     queue_work(dev_priv->wq,
> +                                &dev_priv->hotplug_work);
> +
> +             ret = IRQ_HANDLED;
> +     }
> +
> +     I915_WRITE(VLV_IIR, iir);
> +
> +     I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
> +     POSTING_READ(GEN8_MASTER_IRQ);
> +
> +     return ret;
> +}
> +
>  static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
>  {
>       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> @@ -2985,6 +3074,61 @@ static void gen8_irq_preinstall(struct drm_device *dev)
>       ibx_irq_preinstall(dev);
>  }
>  
> +static void cherryview_irq_preinstall(struct drm_device *dev)
> +{
> +     drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> +     int pipe;
> +
> +     I915_WRITE(GEN8_MASTER_IRQ, 0);
> +     POSTING_READ(GEN8_MASTER_IRQ);
> +
> +/* IIR can theoretically queue up two events. Be paranoid */
> +#define GEN8_IRQ_INIT_NDX(type, which)                               \
> +do {                                                         \
> +     I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff);       \
> +     POSTING_READ(GEN8_##type##_IMR(which));                 \
> +     I915_WRITE(GEN8_##type##_IER(which), 0);                \
> +     I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff);       \
> +     POSTING_READ(GEN8_##type##_IIR(which));                 \
> +     I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff);       \
> +} while (0)
> +
> +#define GEN8_IRQ_INIT(type)                                  \
> +do {                                                         \
> +     I915_WRITE(GEN8_##type##_IMR, 0xffffffff);              \
> +     POSTING_READ(GEN8_##type##_IMR);                        \
> +     I915_WRITE(GEN8_##type##_IER, 0);                       \
> +     I915_WRITE(GEN8_##type##_IIR, 0xffffffff);              \
> +     POSTING_READ(GEN8_##type##_IIR);                        \
> +     I915_WRITE(GEN8_##type##_IIR, 0xffffffff);              \
> +} while (0)
> +
> +     GEN8_IRQ_INIT_NDX(GT, 0);
> +     GEN8_IRQ_INIT_NDX(GT, 1);
> +     GEN8_IRQ_INIT_NDX(GT, 2);
> +     GEN8_IRQ_INIT_NDX(GT, 3);
> +
> +     GEN8_IRQ_INIT(PCU);
> +
> +#undef GEN8_IRQ_INIT
> +#undef GEN8_IRQ_INIT_NDX
> +
> +     POSTING_READ(GEN8_PCU_IIR);
> +
> +     I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
> +
> +     I915_WRITE(PORT_HOTPLUG_EN, 0);
> +     I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
> +
> +     for_each_pipe(pipe)
> +             I915_WRITE(PIPESTAT(pipe), 0xffff);
> +
> +     I915_WRITE(VLV_IMR, 0xffffffff);
> +     I915_WRITE(VLV_IER, 0x0);
> +     I915_WRITE(VLV_IIR, 0xffffffff);
> +     POSTING_READ(VLV_IIR);
> +}
> +
>  static void ibx_hpd_irq_setup(struct drm_device *dev)
>  {
>       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> @@ -3326,6 +3470,50 @@ static int gen8_irq_postinstall(struct drm_device *dev)
>       return 0;
>  }
>  
> +static int cherryview_irq_postinstall(struct drm_device *dev)
> +{
> +     drm_i915_private_t *dev_priv = dev->dev_private;
> +     u32 enable_mask = I915_DISPLAY_PORT_INTERRUPT |
> +             I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
> +             I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
> +             I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
> +             I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT |
> +             I915_DISPLAY_PIPE_C_EVENT_INTERRUPT |
> +             I915_DISPLAY_PIPE_C_VBLANK_INTERRUPT;
> +     u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
> +     unsigned long irqflags;
> +     int pipe;
> +
> +     /*
> +      * Leave vblank interrupts masked initially.  enable/disable will
> +      * toggle them based on usage.
> +      */
> +     dev_priv->irq_mask = ~enable_mask |
> +             I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
> +             I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT |
> +             I915_DISPLAY_PIPE_C_VBLANK_INTERRUPT;
> +
> +     for_each_pipe(pipe)
> +             I915_WRITE(PIPESTAT(pipe), 0xffff);
> +
> +     spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> +     i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
> +     for_each_pipe(pipe)
> +             i915_enable_pipestat(dev_priv, pipe, pipestat_enable);
> +     spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +
> +     I915_WRITE(VLV_IIR, 0xffffffff);
> +     I915_WRITE(VLV_IMR, dev_priv->irq_mask);
> +     I915_WRITE(VLV_IER, enable_mask);
> +
> +     gen8_gt_irq_postinstall(dev_priv);
> +
> +     I915_WRITE(GEN8_MASTER_IRQ, MASTER_INTERRUPT_ENABLE);
> +     POSTING_READ(GEN8_MASTER_IRQ);
> +
> +     return 0;
> +}
> +
>  static void gen8_irq_uninstall(struct drm_device *dev)
>  {
>       struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -3397,6 +3585,57 @@ static void valleyview_irq_uninstall(struct drm_device 
> *dev)
>       POSTING_READ(VLV_IER);
>  }
>  
> +static void cherryview_irq_uninstall(struct drm_device *dev)
> +{
> +     drm_i915_private_t *dev_priv = dev->dev_private;
> +     int pipe;
> +
> +     if (!dev_priv)
> +             return;
> +
> +     I915_WRITE(GEN8_MASTER_IRQ, 0);
> +     POSTING_READ(GEN8_MASTER_IRQ);
> +
> +#define GEN8_IRQ_FINI_NDX(type, which)                               \
> +do {                                                         \
> +     I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff);       \
> +     I915_WRITE(GEN8_##type##_IER(which), 0);                \
> +     I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff);       \
> +     POSTING_READ(GEN8_##type##_IIR(which));                 \
> +     I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff);       \
> +} while (0)
> +
> +#define GEN8_IRQ_FINI(type)                          \
> +do {                                                 \
> +     I915_WRITE(GEN8_##type##_IMR, 0xffffffff);      \
> +     I915_WRITE(GEN8_##type##_IER, 0);               \
> +     I915_WRITE(GEN8_##type##_IIR, 0xffffffff);      \
> +     POSTING_READ(GEN8_##type##_IIR);                \
> +     I915_WRITE(GEN8_##type##_IIR, 0xffffffff);      \
> +} while (0)
> +
> +     GEN8_IRQ_FINI_NDX(GT, 0);
> +     GEN8_IRQ_FINI_NDX(GT, 1);
> +     GEN8_IRQ_FINI_NDX(GT, 2);
> +     GEN8_IRQ_FINI_NDX(GT, 3);
> +
> +     GEN8_IRQ_FINI(PCU);
> +
> +#undef GEN8_IRQ_FINI
> +#undef GEN8_IRQ_FINI_NDX
> +
> +     I915_WRITE(PORT_HOTPLUG_EN, 0);
> +     I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
> +
> +     for_each_pipe(pipe)
> +             I915_WRITE(PIPESTAT(pipe), 0xffff);
> +
> +     I915_WRITE(VLV_IMR, 0xffffffff);
> +     I915_WRITE(VLV_IER, 0x0);
> +     I915_WRITE(VLV_IIR, 0xffffffff);
> +     POSTING_READ(VLV_IIR);
> +}
> +
>  static void ironlake_irq_uninstall(struct drm_device *dev)
>  {
>       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
> @@ -4119,7 +4358,15 @@ void intel_irq_init(struct drm_device *dev)
>               dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
>       }
>  
> -     if (IS_VALLEYVIEW(dev)) {
> +     if (IS_CHERRYVIEW(dev)) {
> +             dev->driver->irq_handler = cherryview_irq_handler;
> +             dev->driver->irq_preinstall = cherryview_irq_preinstall;
> +             dev->driver->irq_postinstall = cherryview_irq_postinstall;
> +             dev->driver->irq_uninstall = cherryview_irq_uninstall;
> +             dev->driver->enable_vblank = valleyview_enable_vblank;
> +             dev->driver->disable_vblank = valleyview_disable_vblank;
> +             dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
> +     } else if (IS_VALLEYVIEW(dev)) {
>               dev->driver->irq_handler = valleyview_irq_handler;
>               dev->driver->irq_preinstall = valleyview_irq_preinstall;
>               dev->driver->irq_postinstall = valleyview_irq_postinstall;
> -- 
> 1.8.3.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to