aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-11 08:05:07 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-11 11:22:53 -0500
commit20afbda209d708be66944907966486d0c1331cb8 (patch)
treeab911fb9ac9ac98654e84129ed1dc3a4adea0a1b
parent9e8e36879f268f1652e11b1c8560bbb67cf4f08e (diff)
drm/i915: Fixup hpd irq register setup ordering
For GMCH platforms we set up the hpd irq registers in the irq postinstall hook. But since we only enable the irq sources we actually need in PORT_HOTPLUG_EN/STATUS, taking dev_priv->hotplug_supported_mask into account, no hpd interrupt sources is enabled since commit 52d7ecedac3f96fb562cb482c139015372728638 Author: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Sat Dec 1 21:03:22 2012 +0100 drm/i915: reorder setup sequence to have irqs for output setup Wrongly set-up interrupts also lead to broken hw-based load-detection on at least GM45, resulting in ghost VGA/TV-out outputs. To fix this, delay the hotplug register setup until after all outputs are set up, by moving it into a new dev_priv->display.hpd_irq_callback. We might also move the PCH_SPLIT platforms to such a setup eventually. Another funny part is that we need to delay the fbdev initial config probing until after the hpd regs are setup, for otherwise it'll detect ghost outputs. But we can only enable the hpd interrupt handling itself (and the output polling) _after_ that initial scan, due to massive locking brain-damage in the fbdev setup code. Add a big comment to explain this cute little dragon lair. v2: Encapsulate all the fbdev handling by wrapping the move call into intel_fbdev_initial_config in intel_fb.c. Requested by Chris Wilson. v3: Applied bikeshed from Jesse Barnes. v4: Imre Deak noticed that we also need to call intel_hpd_init after the drm_irqinstall calls in the gpu reset and resume paths - otherwise hotplug will be broken. Also improve the comment a bit about why hpd_init needs to be called before we set up the initial fbdev config. Bugzilla: Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54943 Reported-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v3) Reviewed-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c15
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c63
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c10
6 files changed, 79 insertions, 14 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 93630669c6dc..0c2ab40ab2ed 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1319,6 +1319,21 @@ static int i915_load_modeset_init(struct drm_device *dev)
1319 goto cleanup_gem; 1319 goto cleanup_gem;
1320 1320
1321 /* Only enable hotplug handling once the fbdev is fully set up. */ 1321 /* Only enable hotplug handling once the fbdev is fully set up. */
1322 intel_hpd_init(dev);
1323
1324 /*
1325 * Some ports require correctly set-up hpd registers for detection to
1326 * work properly (leading to ghost connected connector status), e.g. VGA
1327 * on gm45. Hence we can only set up the initial fbdev config after hpd
1328 * irqs are fully enabled. Now we should scan for the initial config
1329 * only once hotplug handling is enabled, but due to screwed-up locking
1330 * around kms/fbdev init we can't protect the fdbev initial config
1331 * scanning against hotplug events. Hence do this first and ignore the
1332 * tiny window where we will loose hotplug notifactions.
1333 */
1334 intel_fbdev_initial_config(dev);
1335
1336 /* Only enable hotplug handling once the fbdev is fully set up. */
1322 dev_priv->enable_hotplug_processing = true; 1337 dev_priv->enable_hotplug_processing = true;
1323 1338
1324 drm_kms_helper_poll_init(dev); 1339 drm_kms_helper_poll_init(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index a12921892446..fbd0b28b7200 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -566,6 +566,7 @@ static int __i915_drm_thaw(struct drm_device *dev)
566 intel_modeset_init_hw(dev); 566 intel_modeset_init_hw(dev);
567 intel_modeset_setup_hw_state(dev, false); 567 intel_modeset_setup_hw_state(dev, false);
568 drm_irq_install(dev); 568 drm_irq_install(dev);
569 intel_hpd_init(dev);
569 } 570 }
570 571
571 intel_opregion_init(dev); 572 intel_opregion_init(dev);
@@ -871,6 +872,7 @@ int i915_reset(struct drm_device *dev)
871 872
872 drm_irq_uninstall(dev); 873 drm_irq_uninstall(dev);
873 drm_irq_install(dev); 874 drm_irq_install(dev);
875 intel_hpd_init(dev);
874 } else { 876 } else {
875 mutex_unlock(&dev->struct_mutex); 877 mutex_unlock(&dev->struct_mutex);
876 } 878 }
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9da67824dde3..e55303e2f74e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -297,6 +297,7 @@ struct drm_i915_display_funcs {
297 struct drm_i915_gem_object *obj); 297 struct drm_i915_gem_object *obj);
298 int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, 298 int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
299 int x, int y); 299 int x, int y);
300 void (*hpd_irq_setup)(struct drm_device *dev);
300 /* clock updates for mode set */ 301 /* clock updates for mode set */
301 /* cursor updates */ 302 /* cursor updates */
302 /* render clock increase/decrease */ 303 /* render clock increase/decrease */
@@ -1343,6 +1344,7 @@ void i915_hangcheck_elapsed(unsigned long data);
1343void i915_handle_error(struct drm_device *dev, bool wedged); 1344void i915_handle_error(struct drm_device *dev, bool wedged);
1344 1345
1345extern void intel_irq_init(struct drm_device *dev); 1346extern void intel_irq_init(struct drm_device *dev);
1347extern void intel_hpd_init(struct drm_device *dev);
1346extern void intel_gt_init(struct drm_device *dev); 1348extern void intel_gt_init(struct drm_device *dev);
1347extern void intel_gt_reset(struct drm_device *dev); 1349extern void intel_gt_reset(struct drm_device *dev);
1348 1350
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 914ecf4acfa6..551f370657b7 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1995,7 +1995,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
1995{ 1995{
1996 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1996 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1997 u32 enable_mask; 1997 u32 enable_mask;
1998 u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
1999 u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; 1998 u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
2000 u32 render_irqs; 1999 u32 render_irqs;
2001 u16 msid; 2000 u16 msid;
@@ -2024,6 +2023,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
2024 msid |= (1<<14); 2023 msid |= (1<<14);
2025 pci_write_config_word(dev_priv->dev->pdev, 0x98, msid); 2024 pci_write_config_word(dev_priv->dev->pdev, 0x98, msid);
2026 2025
2026 I915_WRITE(PORT_HOTPLUG_EN, 0);
2027 POSTING_READ(PORT_HOTPLUG_EN);
2028
2027 I915_WRITE(VLV_IMR, dev_priv->irq_mask); 2029 I915_WRITE(VLV_IMR, dev_priv->irq_mask);
2028 I915_WRITE(VLV_IER, enable_mask); 2030 I915_WRITE(VLV_IER, enable_mask);
2029 I915_WRITE(VLV_IIR, 0xffffffff); 2031 I915_WRITE(VLV_IIR, 0xffffffff);
@@ -2053,6 +2055,15 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
2053#endif 2055#endif
2054 2056
2055 I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); 2057 I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
2058
2059 return 0;
2060}
2061
2062static void valleyview_hpd_irq_setup(struct drm_device *dev)
2063{
2064 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2065 u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
2066
2056 /* Note HDMI and DP share bits */ 2067 /* Note HDMI and DP share bits */
2057 if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) 2068 if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
2058 hotplug_en |= HDMIB_HOTPLUG_INT_EN; 2069 hotplug_en |= HDMIB_HOTPLUG_INT_EN;
@@ -2070,8 +2081,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
2070 } 2081 }
2071 2082
2072 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 2083 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
2073
2074 return 0;
2075} 2084}
2076 2085
2077static void valleyview_irq_uninstall(struct drm_device *dev) 2086static void valleyview_irq_uninstall(struct drm_device *dev)
@@ -2301,6 +2310,9 @@ static int i915_irq_postinstall(struct drm_device *dev)
2301 I915_USER_INTERRUPT; 2310 I915_USER_INTERRUPT;
2302 2311
2303 if (I915_HAS_HOTPLUG(dev)) { 2312 if (I915_HAS_HOTPLUG(dev)) {
2313 I915_WRITE(PORT_HOTPLUG_EN, 0);
2314 POSTING_READ(PORT_HOTPLUG_EN);
2315
2304 /* Enable in IER... */ 2316 /* Enable in IER... */
2305 enable_mask |= I915_DISPLAY_PORT_INTERRUPT; 2317 enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
2306 /* and unmask in IMR */ 2318 /* and unmask in IMR */
@@ -2311,8 +2323,18 @@ static int i915_irq_postinstall(struct drm_device *dev)
2311 I915_WRITE(IER, enable_mask); 2323 I915_WRITE(IER, enable_mask);
2312 POSTING_READ(IER); 2324 POSTING_READ(IER);
2313 2325
2326 intel_opregion_enable_asle(dev);
2327
2328 return 0;
2329}
2330
2331static void i915_hpd_irq_setup(struct drm_device *dev)
2332{
2333 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2334 u32 hotplug_en;
2335
2314 if (I915_HAS_HOTPLUG(dev)) { 2336 if (I915_HAS_HOTPLUG(dev)) {
2315 u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); 2337 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
2316 2338
2317 if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) 2339 if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
2318 hotplug_en |= HDMIB_HOTPLUG_INT_EN; 2340 hotplug_en |= HDMIB_HOTPLUG_INT_EN;
@@ -2333,10 +2355,6 @@ static int i915_irq_postinstall(struct drm_device *dev)
2333 2355
2334 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 2356 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
2335 } 2357 }
2336
2337 intel_opregion_enable_asle(dev);
2338
2339 return 0;
2340} 2358}
2341 2359
2342static irqreturn_t i915_irq_handler(int irq, void *arg) 2360static irqreturn_t i915_irq_handler(int irq, void *arg)
@@ -2496,7 +2514,6 @@ static void i965_irq_preinstall(struct drm_device * dev)
2496static int i965_irq_postinstall(struct drm_device *dev) 2514static int i965_irq_postinstall(struct drm_device *dev)
2497{ 2515{
2498 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 2516 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2499 u32 hotplug_en;
2500 u32 enable_mask; 2517 u32 enable_mask;
2501 u32 error_mask; 2518 u32 error_mask;
2502 2519
@@ -2538,6 +2555,19 @@ static int i965_irq_postinstall(struct drm_device *dev)
2538 I915_WRITE(IER, enable_mask); 2555 I915_WRITE(IER, enable_mask);
2539 POSTING_READ(IER); 2556 POSTING_READ(IER);
2540 2557
2558 I915_WRITE(PORT_HOTPLUG_EN, 0);
2559 POSTING_READ(PORT_HOTPLUG_EN);
2560
2561 intel_opregion_enable_asle(dev);
2562
2563 return 0;
2564}
2565
2566static void i965_hpd_irq_setup(struct drm_device *dev)
2567{
2568 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
2569 u32 hotplug_en;
2570
2541 /* Note HDMI and DP share hotplug bits */ 2571 /* Note HDMI and DP share hotplug bits */
2542 hotplug_en = 0; 2572 hotplug_en = 0;
2543 if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) 2573 if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
@@ -2572,10 +2602,6 @@ static int i965_irq_postinstall(struct drm_device *dev)
2572 /* Ignore TV since it's buggy */ 2602 /* Ignore TV since it's buggy */
2573 2603
2574 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); 2604 I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
2575
2576 intel_opregion_enable_asle(dev);
2577
2578 return 0;
2579} 2605}
2580 2606
2581static irqreturn_t i965_irq_handler(int irq, void *arg) 2607static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -2754,6 +2780,7 @@ void intel_irq_init(struct drm_device *dev)
2754 dev->driver->irq_uninstall = valleyview_irq_uninstall; 2780 dev->driver->irq_uninstall = valleyview_irq_uninstall;
2755 dev->driver->enable_vblank = valleyview_enable_vblank; 2781 dev->driver->enable_vblank = valleyview_enable_vblank;
2756 dev->driver->disable_vblank = valleyview_disable_vblank; 2782 dev->driver->disable_vblank = valleyview_disable_vblank;
2783 dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup;
2757 } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { 2784 } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
2758 /* Share pre & uninstall handlers with ILK/SNB */ 2785 /* Share pre & uninstall handlers with ILK/SNB */
2759 dev->driver->irq_handler = ivybridge_irq_handler; 2786 dev->driver->irq_handler = ivybridge_irq_handler;
@@ -2780,13 +2807,23 @@ void intel_irq_init(struct drm_device *dev)
2780 dev->driver->irq_postinstall = i915_irq_postinstall; 2807 dev->driver->irq_postinstall = i915_irq_postinstall;
2781 dev->driver->irq_uninstall = i915_irq_uninstall; 2808 dev->driver->irq_uninstall = i915_irq_uninstall;
2782 dev->driver->irq_handler = i915_irq_handler; 2809 dev->driver->irq_handler = i915_irq_handler;
2810 dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
2783 } else { 2811 } else {
2784 dev->driver->irq_preinstall = i965_irq_preinstall; 2812 dev->driver->irq_preinstall = i965_irq_preinstall;
2785 dev->driver->irq_postinstall = i965_irq_postinstall; 2813 dev->driver->irq_postinstall = i965_irq_postinstall;
2786 dev->driver->irq_uninstall = i965_irq_uninstall; 2814 dev->driver->irq_uninstall = i965_irq_uninstall;
2787 dev->driver->irq_handler = i965_irq_handler; 2815 dev->driver->irq_handler = i965_irq_handler;
2816 dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup;
2788 } 2817 }
2789 dev->driver->enable_vblank = i915_enable_vblank; 2818 dev->driver->enable_vblank = i915_enable_vblank;
2790 dev->driver->disable_vblank = i915_disable_vblank; 2819 dev->driver->disable_vblank = i915_disable_vblank;
2791 } 2820 }
2792} 2821}
2822
2823void intel_hpd_init(struct drm_device *dev)
2824{
2825 struct drm_i915_private *dev_priv = dev->dev_private;
2826
2827 if (dev_priv->display.hpd_irq_setup)
2828 dev_priv->display.hpd_irq_setup(dev);
2829}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7ca7772eaccd..22728f2c1d83 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -587,6 +587,7 @@ extern int intel_framebuffer_init(struct drm_device *dev,
587 struct drm_mode_fb_cmd2 *mode_cmd, 587 struct drm_mode_fb_cmd2 *mode_cmd,
588 struct drm_i915_gem_object *obj); 588 struct drm_i915_gem_object *obj);
589extern int intel_fbdev_init(struct drm_device *dev); 589extern int intel_fbdev_init(struct drm_device *dev);
590extern void intel_fbdev_initial_config(struct drm_device *dev);
590extern void intel_fbdev_fini(struct drm_device *dev); 591extern void intel_fbdev_fini(struct drm_device *dev);
591extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); 592extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
592extern void intel_prepare_page_flip(struct drm_device *dev, int plane); 593extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index b7773e548911..822896782cd0 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -243,10 +243,18 @@ int intel_fbdev_init(struct drm_device *dev)
243 } 243 }
244 244
245 drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 245 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
246 drm_fb_helper_initial_config(&ifbdev->helper, 32); 246
247 return 0; 247 return 0;
248} 248}
249 249
250void intel_fbdev_initial_config(struct drm_device *dev)
251{
252 drm_i915_private_t *dev_priv = dev->dev_private;
253
254 /* Due to peculiar init order wrt to hpd handling this is separate. */
255 drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
256}
257
250void intel_fbdev_fini(struct drm_device *dev) 258void intel_fbdev_fini(struct drm_device *dev)
251{ 259{
252 drm_i915_private_t *dev_priv = dev->dev_private; 260 drm_i915_private_t *dev_priv = dev->dev_private;