On Wed, Apr 09, 2014 at 01:28:08PM +0300, ville.syrjala@xxxxxxxxxxxxxxx wrote: > From: Daniel Vetter <daniel.vetter@xxxxxxxx> > > 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.zhao@xxxxxxxxx> > > 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.syrjala@xxxxxxxxxxxxxxx> (v2) > Signed-off-by: Daniel Vetter <daniel.vetter@xxxxxxxx> 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@xxxxxxxxxxxxxxxxxxxxx > 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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx