From c5a44aa012ee86b3dfd0c6050ba34cd6eb412875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:58 +0200 Subject: drm/i915: Fix FBC1 plane checks for gen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On gen2 and gen3 chipsets FBC is supported only on plane A. Fix (and simplify) the plane checks in intel_update_fbc() accordingly. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ff47520f8d4..d389078f0fe 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -537,10 +537,10 @@ void intel_update_fbc(struct drm_device *dev) DRM_DEBUG_KMS("mode too large for compression, disabling\n"); goto out_disable; } - if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) && - intel_crtc->plane != 0) { + if ((INTEL_INFO(dev)->gen < 4 || IS_HASWELL(dev)) && + intel_crtc->plane != PLANE_A) { if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) - DRM_DEBUG_KMS("plane not 0, disabling compression\n"); + DRM_DEBUG_KMS("plane not A, disabling compression\n"); goto out_disable; } -- cgit v1.2.3 From 40045465a91cad4e4bcd2691f0bece5f8b2910e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:59 +0200 Subject: drm/i915: Reorganize FBC function pointer initializaition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize the FBC vfuncs on gen2 and gen3 chipsets. Also make a clean split for gen7+ vs. gen5+ vfunc initialization. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d389078f0fe..ac4a74a4134 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5956,25 +5956,23 @@ void intel_init_pm(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 7) { dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) - dev_priv->display.enable_fbc = - gen7_enable_fbc; - else - dev_priv->display.enable_fbc = - ironlake_enable_fbc; + dev_priv->display.enable_fbc = gen7_enable_fbc; + dev_priv->display.disable_fbc = ironlake_disable_fbc; + } else if (INTEL_INFO(dev)->gen >= 5) { + dev_priv->display.fbc_enabled = ironlake_fbc_enabled; + dev_priv->display.enable_fbc = ironlake_enable_fbc; dev_priv->display.disable_fbc = ironlake_disable_fbc; } else if (IS_GM45(dev)) { dev_priv->display.fbc_enabled = g4x_fbc_enabled; dev_priv->display.enable_fbc = g4x_enable_fbc; dev_priv->display.disable_fbc = g4x_disable_fbc; - } else if (IS_CRESTLINE(dev)) { + } else { dev_priv->display.fbc_enabled = i8xx_fbc_enabled; dev_priv->display.enable_fbc = i8xx_enable_fbc; dev_priv->display.disable_fbc = i8xx_disable_fbc; } - /* 855GM needs testing */ } /* For cxsr */ -- cgit v1.2.3 From d62292c8f778772d1b6ec125d461c8c16fdc0417 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 27 Nov 2013 17:59:22 -0200 Subject: drm/i915: get a PC8 reference when enabling the power well In the current code, at haswell_modeset_global_resources, first we decide if we want to enable/disable the power well, then we decide if we want to enable/disable PC8. On the case where we're enabling PC8 this works fine, but on the case where we disable PC8 due to a non-eDP monitor being enabled, we first enable the power well and then disable PC8. Although wrong, this doesn't seem to be causing any problems now, and we don't even see anything in dmesg. But the patches for runtime D3 turn this problem into a real bug, so we need to fix it. This fixes the "modeset-non-lpsp" subtest from the "pm_pc8" test from intel-gpu-tools. v2: - Rebase (i915_disable_power_well). v3: - More reabase. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 41b6e080e36..cd3f511847e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5688,6 +5688,8 @@ static void hsw_set_power_well(struct drm_device *dev, unsigned long irqflags; uint32_t tmp; + WARN_ON(dev_priv->pc8.enabled); + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED; enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST; @@ -5747,17 +5749,26 @@ static void hsw_set_power_well(struct drm_device *dev, static void __intel_power_well_get(struct drm_device *dev, struct i915_power_well *power_well) { - if (!power_well->count++ && power_well->set) + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!power_well->count++ && power_well->set) { + hsw_disable_package_c8(dev_priv); power_well->set(dev, power_well, true); + } } static void __intel_power_well_put(struct drm_device *dev, struct i915_power_well *power_well) { + struct drm_i915_private *dev_priv = dev->dev_private; + WARN_ON(!power_well->count); - if (!--power_well->count && power_well->set && i915_disable_power_well) + if (!--power_well->count && power_well->set && + i915_disable_power_well) { power_well->set(dev, power_well, false); + hsw_enable_package_c8(dev_priv); + } } void intel_display_power_get(struct drm_device *dev, -- cgit v1.2.3 From 8a1874559f222efcae0c0c41b180f6e1af6b9d2e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Dec 2013 20:32:13 -0200 Subject: drm/i915: add initial Runtime PM functions This patch adds the initial infrastructure to allow a Runtime PM implementation that sets the device to its D3 state. The patch just adds the necessary callbacks and the initial infrastructure. We still don't have any platform that actually uses this infrastructure, we still don't call get/put in all the places we need to, and we don't have any function to save/restore the state of the registers. This is not a problem since no platform uses the code added by this patch. We have a few people simultaneously working on runtime PM, so this initial code could help everybody make their plans. V2: - Move some functions to intel_pm.c - Remove useless pm_runtime_allow() call at init - Remove useless pm_runtime_mark_last_busy() call at get - Use pm_runtime_get_sync() instead of 2 calls - Add a WARN to check if we're really awake V3: - Rebase. V4: - Don't need to call pci_{save,restore}_state and pci_set_power_sate, since they're already called by the PCI layer - Remove wrong pm_runtime_enable() call at init_runtime_pm Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cd3f511847e..2590a5c9072 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -31,6 +31,7 @@ #include "../../../platform/x86/intel_ips.h" #include #include +#include /** * RC6 is a special power stage which allows the GPU to enter an very @@ -5961,6 +5962,60 @@ void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv) hsw_enable_package_c8(dev_priv); } +void intel_runtime_pm_get(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_get_sync(device); + WARN(dev_priv->pm.suspended, "Device still suspended.\n"); +} + +void intel_runtime_pm_put(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_mark_last_busy(device); + pm_runtime_put_autosuspend(device); +} + +void intel_init_runtime_pm(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + dev_priv->pm.suspended = false; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_set_active(device); + + pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */ + pm_runtime_mark_last_busy(device); + pm_runtime_use_autosuspend(device); +} + +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + /* Make sure we're not suspended first. */ + pm_runtime_get_sync(device); + pm_runtime_disable(device); +} + /* Set up chip specific power management-related functions */ void intel_init_pm(struct drm_device *dev) { -- cgit v1.2.3 From d5e8fdc8c10bdff9b8af9cc8b25607ae71e26d3b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 11 Dec 2013 18:50:09 -0200 Subject: drm/i915: extract hsw_power_well_post_{enable, disable} I want to add more code to the post_enable function. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 75 ++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 31 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2590a5c9072..d8fb00a2b56 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5681,12 +5681,53 @@ bool intel_display_power_enabled(struct drm_device *dev, return is_enabled; } +static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + unsigned long irqflags; + + if (IS_BROADWELL(dev)) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), + dev_priv->de_irq_mask[PIPE_B]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), + ~dev_priv->de_irq_mask[PIPE_B] | + GEN8_PIPE_VBLANK); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), + dev_priv->de_irq_mask[PIPE_C]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), + ~dev_priv->de_irq_mask[PIPE_C] | + GEN8_PIPE_VBLANK); + POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } +} + +static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + enum pipe p; + unsigned long irqflags; + + /* + * After this, the registers on the pipes that are part of the power + * well will become zero, so we have to adjust our counters according to + * that. + * + * FIXME: Should we do this in general in drm_vblank_post_modeset? + */ + spin_lock_irqsave(&dev->vbl_lock, irqflags); + for_each_pipe(p) + if (p != PIPE_A) + dev->vblank[p].last = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); +} + static void hsw_set_power_well(struct drm_device *dev, struct i915_power_well *power_well, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; - unsigned long irqflags; uint32_t tmp; WARN_ON(dev_priv->pc8.enabled); @@ -5707,42 +5748,14 @@ static void hsw_set_power_well(struct drm_device *dev, DRM_ERROR("Timeout enabling power well\n"); } - if (IS_BROADWELL(dev)) { - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), - dev_priv->de_irq_mask[PIPE_B]); - I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), - ~dev_priv->de_irq_mask[PIPE_B] | - GEN8_PIPE_VBLANK); - I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), - dev_priv->de_irq_mask[PIPE_C]); - I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), - ~dev_priv->de_irq_mask[PIPE_C] | - GEN8_PIPE_VBLANK); - POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } + hsw_power_well_post_enable(dev_priv); } else { if (enable_requested) { - enum pipe p; - I915_WRITE(HSW_PWR_WELL_DRIVER, 0); POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Requesting to disable the power well\n"); - /* - * After this, the registers on the pipes that are part - * of the power well will become zero, so we have to - * adjust our counters according to that. - * - * FIXME: Should we do this in general in - * drm_vblank_post_modeset? - */ - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for_each_pipe(p) - if (p != PIPE_A) - dev->vblank[p].last = 0; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + hsw_power_well_post_disable(dev_priv); } } } -- cgit v1.2.3 From f9dcb0dfee98406c9c64e1aad10af427d644b78f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 11 Dec 2013 18:50:10 -0200 Subject: drm/i915: touch VGA MSR after we enable the power well Fixes regression introduced by: commit bf51d5e2cda5d36d98e4b46ac7fca9461e512c41 Author: Paulo Zanoni Date: Wed Jul 3 17:12:13 2013 -0300 drm/i915: switch disable_power_well default value to 1 The bug I'm seeing can be reproduced with: - Have vgacon configured/enabled - Make sure the power well gets disabled, then enabled. You can check this by seeing the messages print by hsw_set_power_well - Stop your display manager - echo 0 > /sys/class/vtconsole/vtcon1/bind I can easily reproduce this by blacklising snd_hda_intel and booting with eDP+HDMI. If you do this and then look at dmesg, you'll see we're printing infinite "Unclaimed register" messages. This is happening because we're stuck on an infinite loop inside console_unlock(), which is calling many functions from vgacon.c. And the code that's triggering the error messages is from vgacon_set_cursor_size(). After we re-enable the power well, every time we read/write the VGA address 0x3d5 we get an "unclaimed register" interrupt (ERR_INT) and print error messages. If we write anything to the VGA MSR register (it doesn't really matter which value you write to bit 0), any reads/writes to 0x3d5 _don't_ trigger the "unclaimed register" errors anymore (even if MSR bit 0 is zero). So what happens with the current code is that when we unbind i915 and bind vgacon, we call console_unlock(). Function console_unlock() is responsible for printing any messages that were supposed to be print when the console was locked, so it calls the TTY layer, which calls the console layer, which calls vgacon to print the messages. At this point, vgacon eventually calls vgacon_set_cursor_size(), which touches 0x3d5, which triggers unclaimed register interrupts. The problem is that when we get these interrupts, we print the error messages, so we add more work to console_unlock(), which will try to print it again, and then call vgacon again, trigger a new interrupt, which will put more stuff to the buffer, and then we'll be stuck at console_unlock() forever. If you patch intel_uncore.c to not print anything when we detect unclaimed registers, we won't get into the console_unlock() infinite loop and the driver unbind will work just fine. We will still be getting interrupts every time vgacon touches those registers, but we will survive. This is a valid experiment, but IMHO it's not the real fix: if we don't print any error messages we will still keep getting the interrupts, and if we disable ERR_INT we won't get the interrupt anymore, but we will also stop getting all the other error interrupts. I talked about this problem with the HW engineer and his recommendation is "So don't do any VGA I/O or memory access while the power well is disabled, and make to re-program MSR after enabling the power well and before using VGA I/O or memory accesses.". Notice that this is just a partial fix to fd.o #67813. This fixes the case where the power well is already enabled when we unbind, not when it's disabled when we unbind. V2: - Rebase (first version was sent in September). V3: - Complete rewrite of the same fix: smaller implementation, improved commit message. Testcase: igt/drv_module_reload Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=67813 Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d8fb00a2b56..3cd521f3823 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -30,6 +30,7 @@ #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" #include +#include #include #include @@ -5686,6 +5687,20 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; unsigned long irqflags; + /* + * After we re-enable the power well, if we touch VGA register 0x3d5 + * we'll get unclaimed register interrupts. This stops after we write + * anything to the VGA MSR register. The vgacon module uses this + * register all the time, so if we unbind our driver and, as a + * consequence, bind vgacon, we'll get stuck in an infinite loop at + * console_unlock(). So make here we touch the VGA MSR register, making + * sure vgacon can keep working normally without triggering interrupts + * and error messages. + */ + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); + outb(inb(VGA_MSR_READ), VGA_MSR_WRITE); + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); + if (IS_BROADWELL(dev)) { spin_lock_irqsave(&dev_priv->irq_lock, irqflags); I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), -- cgit v1.2.3 From 42a430f51c7500be41ca4cbd5b3de930853bd5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:56 +0200 Subject: drm/i915: Gen2 FBC1 CFB pitch wants 32B units MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On gen2 the compressed frame buffer pitch is specified in 32B units rather than the 64B units used on gen3+. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3cd521f3823..599d445f7ce 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -104,8 +104,11 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) if (fb->pitches[0] < cfb_pitch) cfb_pitch = fb->pitches[0]; - /* FBC_CTL wants 64B units */ - cfb_pitch = (cfb_pitch / 64) - 1; + /* FBC_CTL wants 32B or 64B units */ + if (IS_GEN2(dev)) + cfb_pitch = (cfb_pitch / 32) - 1; + else + cfb_pitch = (cfb_pitch / 64) - 1; plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; /* Clear old tags */ -- cgit v1.2.3 From 159f98750e413f5d6e63d1131417c5310ea175fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Nov 2013 17:29:57 +0200 Subject: drm/i915: FBC_CONTROL2 is gen4 only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gen2 and gen3 don't have the FBC_CONTROL2 register, so don't touch it. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 599d445f7ce..d7cb6bf5712 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -98,7 +98,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int cfb_pitch; int plane, i; - u32 fbc_ctl, fbc_ctl2; + u32 fbc_ctl; cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; if (fb->pitches[0] < cfb_pitch) @@ -115,11 +115,15 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) I915_WRITE(FBC_TAG + (i * 4), 0); - /* Set it up... */ - fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= plane; - I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); + if (IS_GEN4(dev)) { + u32 fbc_ctl2; + + /* Set it up... */ + fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; + fbc_ctl2 |= plane; + I915_WRITE(FBC_CONTROL2, fbc_ctl2); + I915_WRITE(FBC_FENCE_OFF, crtc->y); + } /* enable it... */ fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; -- cgit v1.2.3 From 993495ae992c91e98ade8fbe977c57bfd81910c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 12 Dec 2013 17:27:40 +0200 Subject: drm/i915: Rework the FBC interval/stall stuff a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't touch DPFC_RECOMP_CTL on FBC2, use RMW to update the FBC_CONTROL on FBC1 to make it easier for people to experiment with different numbers. Also fix the interval mask for FBC1. v2: Rebased Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d7cb6bf5712..c68abf71882 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -88,7 +88,7 @@ static void i8xx_disable_fbc(struct drm_device *dev) DRM_DEBUG_KMS("disabled FBC\n"); } -static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void i8xx_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -126,11 +126,12 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) } /* enable it... */ - fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + fbc_ctl = I915_READ(FBC_CONTROL); + fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; if (IS_I945GM(dev)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; fbc_ctl |= obj->fence_reg; I915_WRITE(FBC_CONTROL, fbc_ctl); @@ -145,7 +146,7 @@ static bool i8xx_fbc_enabled(struct drm_device *dev) return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void g4x_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -154,16 +155,12 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; u32 dpfc_ctl; dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); - I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(DPFC_FENCE_YOFF, crtc->y); /* enable it... */ @@ -219,7 +216,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA); } -static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void ironlake_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -228,7 +225,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; u32 dpfc_ctl; dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); @@ -241,9 +237,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl |= obj->fence_reg; I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); - I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); /* enable it... */ @@ -281,7 +274,7 @@ static bool ironlake_fbc_enabled(struct drm_device *dev) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } -static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void gen7_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -338,8 +331,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) * the prior work. */ if (work->crtc->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc, - work->interval); + dev_priv->display.enable_fbc(work->crtc); dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane; dev_priv->fbc.fb_id = work->crtc->fb->base.id; @@ -376,7 +368,7 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) dev_priv->fbc.fbc_work = NULL; } -static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void intel_enable_fbc(struct drm_crtc *crtc) { struct intel_fbc_work *work; struct drm_device *dev = crtc->dev; @@ -390,13 +382,12 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) work = kzalloc(sizeof(*work), GFP_KERNEL); if (work == NULL) { DRM_ERROR("Failed to allocate FBC work structure\n"); - dev_priv->display.enable_fbc(crtc, interval); + dev_priv->display.enable_fbc(crtc); return; } work->crtc = crtc; work->fb = crtc->fb; - work->interval = interval; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); dev_priv->fbc.fbc_work = work; @@ -611,7 +602,7 @@ void intel_update_fbc(struct drm_device *dev) intel_disable_fbc(dev); } - intel_enable_fbc(crtc, 500); + intel_enable_fbc(crtc); dev_priv->fbc.no_fbc_reason = FBC_OK; return; @@ -6073,6 +6064,9 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.fbc_enabled = i8xx_fbc_enabled; dev_priv->display.enable_fbc = i8xx_enable_fbc; dev_priv->display.disable_fbc = i8xx_disable_fbc; + + /* This value was pulled out of someone's hat */ + I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } } -- cgit v1.2.3 From 63801f211c6eeb6def635ceee39d165e00fd6e09 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 12 Dec 2013 17:26:03 -0800 Subject: drm/i915/bdw: Force all Data Cache Data Port access to be Non-Coherent I stumbled on to some unimplemented errata. To be honest, I am not really sure of the impact, just that the docs say to do. No w/a name for this one. v2: v1 was a stale thing which should have never seen the light of day. (Haihao) Cc: Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c68abf71882..791fbe386b7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5269,6 +5269,14 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_READ(CHICKEN_PIPESL_1(i) | DPRS_MASK_VBLANK_SRD)); } + + /* Use Force Non-Coherent whenever executing a 3D context. This is a + * workaround for for a possible hang in the unlikely event a TLB + * invalidation occurs during a PSD flush. + */ + I915_WRITE(HDC_CHICKEN0, + I915_READ(HDC_CHICKEN0) | + _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT)); } static void haswell_init_clock_gating(struct drm_device *dev) -- cgit v1.2.3 From ab57fff1302c485d74992d34df24ccb5efda244e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 12 Dec 2013 15:28:04 -0800 Subject: drm/i915/bdw: Implement ff workarounds WaVSRefCountFullforceMissDisable and WaDSRefCountFullforceMissDisable VS is a carry-over from HSW, and DS is likely not used by anyone yet. Cc: Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau [danvet: Line of 106 chars is too long. Really.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_pm.c') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 791fbe386b7..b35f65ed6c5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5256,14 +5256,14 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE)); - /* WaSwitchSolVfFArbitrationPriority */ + /* WaSwitchSolVfFArbitrationPriority:bdw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); - /* WaPsrDPAMaskVBlankInSRD */ + /* WaPsrDPAMaskVBlankInSRD:bdw */ I915_WRITE(CHICKEN_PAR1_1, I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD); - /* WaPsrDPRSUnmaskVBlankInSRD */ + /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ for_each_pipe(i) { I915_WRITE(CHICKEN_PIPESL_1(i), I915_READ(CHICKEN_PIPESL_1(i) | @@ -5277,6 +5277,12 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(HDC_CHICKEN0, I915_READ(HDC_CHICKEN0) | _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT)); + + /* WaVSRefCountFullforceMissDisable:bdw */ + /* WaDSRefCountFullforceMissDisable:bdw */ + I915_WRITE(GEN7_FF_THREAD_MODE, + I915_READ(GEN7_FF_THREAD_MODE) & + ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME)); } static void haswell_init_clock_gating(struct drm_device *dev) -- cgit v1.2.3