From cace841cece3b2d6c26af2f6adb9d0752d95c849 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 May 2014 17:56:31 +0200 Subject: drm/i915: Add fifo underrun reporting state to debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms with shared interrupt enable bits (which are shared even with the pipe CRC logic) there's some tricky corner cases. Add information to make debugging those easier. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 169fc2d8c554..98ab492ee60a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2357,6 +2357,10 @@ static int i915_display_info(struct seq_file *m, void *unused) x, y, crtc->cursor_addr, yesno(active)); } + + seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s \n", + yesno(!crtc->cpu_fifo_underrun_disabled), + yesno(!crtc->pch_fifo_underrun_disabled)); } seq_printf(m, "\n"); -- cgit v1.2.3 From 2ae2a50c956665da82cf9e9582ae1ade082fee75 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 May 2014 17:56:32 +0200 Subject: drm/i915: Fix up fifo underrun tracking, take N MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So apparently this is tricky. We need to consider: - We start out with all the hw enabling bits disabled, both the individual fifo underrun interrupts and the shared display error interrupts masked. Otherwise if the bios config is broken we'll blow up with a NULL deref in our interrupt handler since the crtc structures aren't set up yet at driver load time. - On gmch we need to mask fifo underruns on the sw side, so always need to set that in sanitize_crtc for those platforms. - On other platforms we try to set the sw tracking so that it reflects the real state. But since a few platforms have shared bits we must _not_ disable fifo underrun reporting. Otherwise we'll never enable the shared error interrupt. This is the state before out patch, but unfortunately this is not good enough. But after a suspend resume operation this is broken: 1. We don't enable the hw interrupts since the same code runs on resume as on driver load. 2. The fifo underrun state adjustments we do in sanitize_crtc doesn't fire on resume since (except for hilarious firmware) all pipes are off at that point. But they also don't hurt since the subsequent crtc enabling due to force_restore will enable fifo underruns. Which means when we enable fifo underrun reporting we notice that the per-crtc state is already correct and short-circuit everthing out. And the interrupt doesn't get enabled. A similar problem would happen if the bios doesn't light up anything when the driver loads. Which is exactly what happens when we reload the driver since our unload functions disables all outputs. Now we can't just rip out the short-circuit logic and unconditionally update the fifo underrun reporting interrupt masking: We have some checks for shared error interrupts to catch issues that happened when the shared error interrupt was disabled. The right fix is to push down this logic so that we can always update the hardware state, but only check for missed fifo underruns on a real enabled->disabled transition and ignore them when we're already disabled. On platforms with shared error interrupt the pipe CRC interrupts are grouped together with the fifo underrun reporting this fixes pipe CRC support after suspend and driver reloads. Testcase: igt/kms_pipe_crc_basic/suspend-* Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 44 ++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cbf31cbfa084..657a7e32e166 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -335,7 +335,8 @@ void i9xx_check_fifo_underruns(struct drm_device *dev) } static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, - enum pipe pipe, bool enable) + enum pipe pipe, + bool enable, bool old) { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg = PIPESTAT(pipe); @@ -347,7 +348,7 @@ static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); POSTING_READ(reg); } else { - if (pipestat & PIPE_FIFO_UNDERRUN_STATUS) + if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS) DRM_ERROR("pipe %c underrun\n", pipe_name(pipe)); } } @@ -366,7 +367,8 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, } static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, - enum pipe pipe, bool enable) + enum pipe pipe, + bool enable, bool old) { struct drm_i915_private *dev_priv = dev->dev_private; if (enable) { @@ -379,7 +381,8 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, } else { ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); - if (I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) { + if (old && + I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) { DRM_ERROR("uncleared fifo underrun on pipe %c\n", pipe_name(pipe)); } @@ -444,7 +447,7 @@ static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, enum transcoder pch_transcoder, - bool enable) + bool enable, bool old) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -459,7 +462,8 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, } else { ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); - if (I915_READ(SERR_INT) & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) { + if (old && I915_READ(SERR_INT) & + SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) { DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n", transcoder_name(pch_transcoder)); } @@ -486,28 +490,23 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - bool ret; + bool old; assert_spin_locked(&dev_priv->irq_lock); - ret = !intel_crtc->cpu_fifo_underrun_disabled; - - if (enable == ret) - goto done; - + old = !intel_crtc->cpu_fifo_underrun_disabled; intel_crtc->cpu_fifo_underrun_disabled = !enable; if (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)) - i9xx_set_fifo_underrun_reporting(dev, pipe, enable); + i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old); else if (IS_GEN5(dev) || IS_GEN6(dev)) ironlake_set_fifo_underrun_reporting(dev, pipe, enable); else if (IS_GEN7(dev)) - ivybridge_set_fifo_underrun_reporting(dev, pipe, enable); + ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old); else if (IS_GEN8(dev)) broadwell_set_fifo_underrun_reporting(dev, pipe, enable); -done: - return ret; + return old; } bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, @@ -556,7 +555,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); unsigned long flags; - bool ret; + bool old; /* * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT @@ -569,21 +568,16 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, spin_lock_irqsave(&dev_priv->irq_lock, flags); - ret = !intel_crtc->pch_fifo_underrun_disabled; - - if (enable == ret) - goto done; - + old = !intel_crtc->pch_fifo_underrun_disabled; intel_crtc->pch_fifo_underrun_disabled = !enable; if (HAS_PCH_IBX(dev)) ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); else - cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable); + cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old); -done: spin_unlock_irqrestore(&dev_priv->irq_lock, flags); - return ret; + return old; } -- cgit v1.2.3 From 85ab3998c6ea28e2794a63b58cf52b634de1ddac Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 May 2014 17:56:33 +0200 Subject: drm/i915: Disable gpu reset on i965g/gm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville figured out that it needs a full display reset since apparently a lot more goes down than just the GT. Until that's address it's better to just diable gpu reset. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_uncore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 9cd99d9676fd..1dbabb071c08 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -965,6 +965,9 @@ static int i965_do_reset(struct drm_device *dev) { int ret; + /* FIXME: i965g/gm need a display save/restore for gpu reset. */ + return -ENODEV; + /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as * well as the reset bit (GR/bit 0). Setting the GR bit -- cgit v1.2.3 From 723761b88adac0e90f80a32caf4c54461b4105a7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 May 2014 17:56:34 +0200 Subject: drm/i915: Inline ilk/gen8_irq_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No point in having this indirection. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 657a7e32e166..c11fa4292f68 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3111,11 +3111,6 @@ static void ironlake_irq_reset(struct drm_device *dev) ibx_irq_reset(dev); } -static void ironlake_irq_preinstall(struct drm_device *dev) -{ - ironlake_irq_reset(dev); -} - static void valleyview_irq_preinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3168,11 +3163,6 @@ static void gen8_irq_reset(struct drm_device *dev) ibx_irq_reset(dev); } -static void gen8_irq_preinstall(struct drm_device *dev) -{ - gen8_irq_reset(dev); -} - static void cherryview_irq_preinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4381,7 +4371,7 @@ void intel_irq_init(struct drm_device *dev) dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else if (IS_GEN8(dev)) { dev->driver->irq_handler = gen8_irq_handler; - dev->driver->irq_preinstall = gen8_irq_preinstall; + dev->driver->irq_preinstall = gen8_irq_reset; dev->driver->irq_postinstall = gen8_irq_postinstall; dev->driver->irq_uninstall = gen8_irq_uninstall; dev->driver->enable_vblank = gen8_enable_vblank; @@ -4389,7 +4379,7 @@ void intel_irq_init(struct drm_device *dev) dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; - dev->driver->irq_preinstall = ironlake_irq_preinstall; + dev->driver->irq_preinstall = ironlake_irq_reset; dev->driver->irq_postinstall = ironlake_irq_postinstall; dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ironlake_enable_vblank; -- cgit v1.2.3 From 78ad455fd229c6f6cc2f390ccbe0d8f1a62d55a9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 May 2014 22:18:21 +0200 Subject: drm/i915: Improve irq handling after gpu resets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we do a full re-init of all interrupts after a gpu hang. Which is pretty bad since we don't restore the interrupts we've enabled at runtime correctly. Even with that addressed it's rather horribly race. But on g4x and later we only reset the gt and not the entire gpu. Which means we only need to reset the GT interrupt bits. Which has the nice benefit that vblank waits, pipe CRC interrupts and everything else display related just keeps on working. The downside is that gt interrupt handling (i.e. ring->get/put_irq) is still racy. But as long as the gpu hang reliably wakes all waters and we have a short time where the refcount drops to 0 we'll recover. So not that bad really. v2: Ville noticed that GTIMR and PMIMR don't get cleared, only the subordinate per-ring registers. So let's rip out all the interrupt dancing. The FIXME comment is still required though since the ring irq handling happens at the per-ring interrupt mask registers, too. Testcase: igt/kms_flip/vblank-vs-hang Testcase: igt/kms_pipe_crc_basic/hang-* Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5b5b82c3f570..481d2a14cdc6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -811,17 +811,17 @@ int i915_reset(struct drm_device *dev) } /* - * FIXME: This is horribly race against concurrent pageflip and - * vblank wait ioctls since they can observe dev->irqs_disabled - * being false when they shouldn't be able to. + * FIXME: This races pretty badly against concurrent holders of + * ring interrupts. This is possible since we've started to drop + * dev->struct_mutex in select places when waiting for the gpu. */ - drm_irq_uninstall(dev); - drm_irq_install(dev, dev->pdev->irq); - /* rps/rc6 re-init is necessary to restore state lost after the - * reset and the re-install of drm irq. Skip for ironlake per + /* + * rps/rc6 re-init is necessary to restore state lost after the + * reset and the re-install of gt irqs. Skip for ironlake per * previous concerns that it doesn't respond well to some forms - * of re-init after reset. */ + * of re-init after reset. + */ if (INTEL_INFO(dev)->gen > 5) intel_reset_gt_powersave(dev); -- cgit v1.2.3 From d6e3cca31e4116a1fcfe4249a4cbd18183544f0d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 May 2014 22:18:22 +0200 Subject: drm/i915: Extract gen8_gt_irq_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fallout from an intermediate patch revision that I deemed worth saving. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c11fa4292f68..7f3568d2a1de 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3140,6 +3140,14 @@ static void valleyview_irq_preinstall(struct drm_device *dev) POSTING_READ(VLV_IER); } +static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv) +{ + GEN8_IRQ_RESET_NDX(GT, 0); + GEN8_IRQ_RESET_NDX(GT, 1); + GEN8_IRQ_RESET_NDX(GT, 2); + GEN8_IRQ_RESET_NDX(GT, 3); +} + static void gen8_irq_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3148,10 +3156,7 @@ static void gen8_irq_reset(struct drm_device *dev) I915_WRITE(GEN8_MASTER_IRQ, 0); POSTING_READ(GEN8_MASTER_IRQ); - GEN8_IRQ_RESET_NDX(GT, 0); - GEN8_IRQ_RESET_NDX(GT, 1); - GEN8_IRQ_RESET_NDX(GT, 2); - GEN8_IRQ_RESET_NDX(GT, 3); + gen8_gt_irq_reset(dev_priv); for_each_pipe(pipe) GEN8_IRQ_RESET_NDX(DE_PIPE, pipe); @@ -3171,10 +3176,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev) I915_WRITE(GEN8_MASTER_IRQ, 0); POSTING_READ(GEN8_MASTER_IRQ); - GEN8_IRQ_RESET_NDX(GT, 0); - GEN8_IRQ_RESET_NDX(GT, 1); - GEN8_IRQ_RESET_NDX(GT, 2); - GEN8_IRQ_RESET_NDX(GT, 3); + gen8_gt_irq_reset(dev_priv); GEN5_IRQ_RESET(GEN8_PCU_); -- cgit v1.2.3 From 2ab8b458c6a1c784a1edc4308d920f97c0e2a2b8 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 23 May 2014 21:35:27 +0530 Subject: drm/i915: Add support for Generic MIPI panel driver This driver makes use of the generic panel information from the VBT. Panel information is classified into two - panel configuration and panel power sequence which is unique to each panel. The generic driver uses the panel configuration and sequence parsed from VBT block #52 and #53 v2: Address review comments by Jani - Move all of the things in driver c file from header - Make all functions static - Make use of video/mipi_display.c instead of redefining - Null checks during sequence execution v3: Address review comments by Damien - Rename the panel driver file as intel_dsi_panel_vbt.c - Fix style changes as suggested - Correct comments for lp->hs and hs->lp count calculations - General updating comments to have more clarity - using max() instead of ternary operator - Fix names (ui_num, ui_den) while using UI in calculations - compute max of lp_to_hs switch and hs_to_lp switch while computing hs_lp_switch_count Signed-off-by: Shobhit Kumar Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/intel_dsi.c | 5 + drivers/gpu/drm/i915/intel_dsi.h | 2 + drivers/gpu/drm/i915/intel_dsi_panel_vbt.c | 589 +++++++++++++++++++++++++++++ 4 files changed, 597 insertions(+) create mode 100644 drivers/gpu/drm/i915/intel_dsi_panel_vbt.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7b2f3bee3518..cad1683d8bb5 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -62,6 +62,7 @@ i915-y += dvo_ch7017.o \ intel_dsi_cmd.o \ intel_dsi.o \ intel_dsi_pll.o \ + intel_dsi_panel_vbt.o \ intel_dvo.o \ intel_hdmi.o \ intel_i2c.o \ diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 2525cdd52343..e73bec616904 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -35,6 +35,11 @@ /* the sub-encoders aka panel drivers */ static const struct intel_dsi_device intel_dsi_devices[] = { + { + .panel_id = MIPI_DSI_GENERIC_PANEL_ID, + .name = "vbt-generic-dsi-vid-mode-display", + .dev_ops = &vbt_generic_dsi_display_ops, + }, }; static void band_gap_reset(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index e3f4e91c526f..31db33d3e5cc 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -133,4 +133,6 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) extern void vlv_enable_dsi_pll(struct intel_encoder *encoder); extern void vlv_disable_dsi_pll(struct intel_encoder *encoder); +extern struct intel_dsi_dev_ops vbt_generic_dsi_display_ops; + #endif /* _INTEL_DSI_H */ diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c new file mode 100644 index 000000000000..21a0d348cedc --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -0,0 +1,589 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Shobhit Kumar + * + */ + +#include +#include +#include +#include +#include +#include