diff options
author | Dave Airlie <airlied@redhat.com> | 2013-02-20 05:40:49 +0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-02-20 05:41:26 +0400 |
commit | b81e059ec5a7128622ab5d74d78e9b4f361b54ae (patch) | |
tree | 65344a0adc351fd0a14a14d9fa50e93b69a5bb6e /drivers/gpu/drm/i915 | |
parent | 35f8badc1cf652381fa3f82c1fbea39f4dbe87fd (diff) | |
parent | 210561ffd72d00eccf12c0131b8024d5436bae95 (diff) | |
download | linux-b81e059ec5a7128622ab5d74d78e9b4f361b54ae.tar.xz |
Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel into drm-next
So here's my promised pile of fixes for 3.9. I've dropped the core prep
patches for vt-switchless suspend/resume as discussed on irc. Highlights:
- Fix dmar on g4x. Not really gfx related, but I'm fed up with getting
blamed for dmar crapouts.
- Disable wc ptes updates on ilk when dmar is enabled (Chris). So again,
dmar, but this time gfx related :(
- Reduced range support for hsw, using the pipe CSC (Ville).
- Fixup pll limits for gen3/4 (Patrick Jakobsson). The sdvo patch is
already confirmed to fix 2 bug reports, so added cc: stable on that one.
- Regression fix for 8bit fb console (Ville).
- Preserve lane reversal bits on DDI/FDI ports (Damien).
- Page flip vs. gpu hang fixes (Ville). Unfortuntely not quite all of
them, need to decide what to do with the currently still in-flight ones.
- Panel fitter regression fix from Mika Kuoppala (was accidentally left on
on some pipes with the new modset code since 3.7). This also improves
the modeset sequence and might help a few other unrelated issues with
lvds.
- Write backlight regs even harder ... another installement in our eternal
fight against the BIOS and backlights.
- Fixup lid notifier vs. suspend/resume races (Zhang Rui). Prep work for
new ACPI stuff, but closing the race itself seems worthwile on its own.
- A few other small fixes and tiny cleanups all over.
Lots of the patches are cc: stable since I've stalled on a few
not-so-important fixes for 3.8 due to the grumpy noise Linus made.
* 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel: (33 commits)
intel/iommu: force writebuffer-flush quirk on Gen 4 Chipsets
drm/i915: Disable WC PTE updates to w/a buggy IOMMU on ILK
drm/i915: Implement pipe CSC based limited range RGB output
drm/i915: inverted brightness quirk for Acer Aspire 4736Z
drm/i915: Print the hw context status is debugfs
drm/i915: Use HAS_L3_GPU_CACHE in i915_gem_l3_remap
drm/i915: Fix PIPE_CONTROL DW/QW write through global GTT on IVB+
drm/i915: Set i9xx sdvo clock limits according to specifications
drm/i915: Set i9xx lvds clock limits according to specifications
drm/i915: Preserve the DDI link reversal configuration
drm/i915: Preserve the FDI line reversal override bit on CPT
drm/i915: add missing \n to UTS_RELEASE in the error_state
drm: Use C8 instead of RGB332 when determining the format from depth/bpp
drm: Fill depth/bits_per_pixel for C8 format
drm/i915: don't clflush gem objects in stolen memory
drm/i915: Don't wait for page flips if there was GPU reset
drm/i915: Kill obj->pending_flip
drm/i915: Fix a typo in a intel_modeset_stage_output_state() comment
drm/i915: remove bogus mutex_unlock from error-path
drm/i915: Print the pipe control page GTT address
...
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 62 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_context.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 92 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 108 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_sprite.c | 30 |
20 files changed, 432 insertions, 232 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e0e77b89d114..7c65ab83914a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -694,7 +694,7 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); - seq_printf(m, "Kernel: " UTS_RELEASE); + seq_printf(m, "Kernel: " UTS_RELEASE "\n"); seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); seq_printf(m, "EIR: 0x%08x\n", error->eir); seq_printf(m, "IER: 0x%08x\n", error->ier); @@ -1484,7 +1484,8 @@ static int i915_context_status(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + struct intel_ring_buffer *ring; + int ret, i; ret = mutex_lock_interruptible(&dev->mode_config.mutex); if (ret) @@ -1502,6 +1503,14 @@ static int i915_context_status(struct seq_file *m, void *unused) seq_printf(m, "\n"); } + for_each_ring(ring, dev_priv, i) { + if (ring->default_context) { + seq_printf(m, "HW default context %s ring ", ring->name); + describe_obj(m, ring->default_context->obj); + seq_printf(m, "\n"); + } + } + mutex_unlock(&dev->mode_config.mutex); return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index cf0610330135..4fa6beb14c77 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1610,6 +1610,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->rps.hw_lock); + mutex_init(&dev_priv->modeset_restore_lock); if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d159d7a402e9..c5b8c81b9440 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -470,6 +470,11 @@ static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + /* ignore lid events during suspend */ + mutex_lock(&dev_priv->modeset_restore_lock); + dev_priv->modeset_restore = MODESET_SUSPENDED; + mutex_unlock(&dev_priv->modeset_restore_lock); + intel_set_power_well(dev, true); drm_kms_helper_poll_disable(dev); @@ -496,9 +501,6 @@ static int i915_drm_freeze(struct drm_device *dev) intel_opregion_fini(dev); - /* Modeset on resume, not lid events */ - dev_priv->modeset_on_lid = 0; - console_lock(); intel_fbdev_set_suspend(dev, 1); console_unlock(); @@ -574,8 +576,6 @@ static int __i915_drm_thaw(struct drm_device *dev) intel_opregion_init(dev); - dev_priv->modeset_on_lid = 0; - /* * The console lock can be pretty contented on resume due * to all the printk activity. Try to keep it out of the hot @@ -588,6 +588,9 @@ static int __i915_drm_thaw(struct drm_device *dev) schedule_work(&dev_priv->console_resume_work); } + mutex_lock(&dev_priv->modeset_restore_lock); + dev_priv->modeset_restore = MODESET_DONE; + mutex_unlock(&dev_priv->modeset_restore_lock); return error; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c338b4443fd9..e95337c97459 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -399,7 +399,8 @@ struct i915_gtt { /* global gtt ops */ int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, - size_t *stolen); + size_t *stolen, phys_addr_t *mappable_base, + unsigned long *mappable_end); void (*gtt_remove)(struct drm_device *dev); void (*gtt_clear_range)(struct drm_device *dev, unsigned int first_entry, @@ -846,6 +847,12 @@ struct i915_gpu_error { unsigned int stop_rings; }; +enum modeset_restore { + MODESET_ON_LID_OPEN, + MODESET_DONE, + MODESET_SUSPENDED, +}; + typedef struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -919,7 +926,7 @@ typedef struct drm_i915_private { /* overlay */ struct intel_overlay *overlay; - bool sprite_scaling_enabled; + unsigned int sprite_scaling_enabled; /* LVDS info */ int backlight_level; /* restore backlight to this value */ @@ -967,8 +974,8 @@ typedef struct drm_i915_private { unsigned long quirks; - /* Register state */ - bool modeset_on_lid; + enum modeset_restore modeset_restore; + struct mutex modeset_restore_lock; struct i915_gtt gtt; @@ -1033,7 +1040,7 @@ typedef struct drm_i915_private { bool hw_contexts_disabled; uint32_t hw_context_size; - bool fdi_rx_polarity_reversed; + u32 fdi_rx_config; struct i915_suspend_saved_registers regfile; @@ -1208,13 +1215,6 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; - - /** - * Number of crtcs where this object is currently the fb, but - * will be page flipped away on the next vblank. When it - * reaches 0, dev_priv->pending_flip_queue will be woken up. - */ - atomic_t pending_flip; }; #define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 62be74899c2b..8413ffced815 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3021,6 +3021,13 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) if (obj->pages == NULL) return; + /* + * Stolen memory is always coherent with the GPU as it is explicitly + * marked as wc by the system, or the system is cache-coherent. + */ + if (obj->stolen) + return; + /* If the GPU is snooping the contents of the CPU cache, * we do not need to manually clear the CPU cache lines. However, * the caches are only snooped when the render cache is @@ -3865,7 +3872,7 @@ void i915_gem_l3_remap(struct drm_device *dev) u32 misccpctl; int i; - if (!IS_IVYBRIDGE(dev)) + if (!HAS_L3_GPU_CACHE(dev)) return; if (!dev_priv->l3_parity.remap_info) @@ -3930,22 +3937,11 @@ intel_enable_blt(struct drm_device *dev) return true; } -int -i915_gem_init_hw(struct drm_device *dev) +static int i915_gem_init_rings(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) - return -EIO; - - if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) - I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); - - i915_gem_l3_remap(dev); - - i915_gem_init_swizzling(dev); - ret = intel_init_render_ring_buffer(dev); if (ret) return ret; @@ -3964,6 +3960,38 @@ i915_gem_init_hw(struct drm_device *dev) ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); if (ret) + goto cleanup_blt_ring; + + return 0; + +cleanup_blt_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[BCS]); +cleanup_bsd_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); +cleanup_render_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); + + return ret; +} + +int +i915_gem_init_hw(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) + return -EIO; + + if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) + I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); + + i915_gem_l3_remap(dev); + + i915_gem_init_swizzling(dev); + + ret = i915_gem_init_rings(dev); + if (ret) return ret; /* @@ -3974,12 +4002,6 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_init_ppgtt(dev); return 0; - -cleanup_bsd_ring: - intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); -cleanup_render_ring: - intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); - return ret; } int i915_gem_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a3f06bcad551..21177d9df423 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -126,13 +126,8 @@ static int get_context_size(struct drm_device *dev) static void do_destroy(struct i915_hw_context *ctx) { - struct drm_device *dev = ctx->obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - if (ctx->file_priv) idr_remove(&ctx->file_priv->context_idr, ctx->id); - else - BUG_ON(ctx != dev_priv->ring[RCS].default_context); drm_gem_object_unreference(&ctx->obj->base); kfree(ctx); @@ -242,7 +237,6 @@ err_destroy: void i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ctx_size; if (!HAS_HW_CONTEXTS(dev)) { dev_priv->hw_contexts_disabled = true; @@ -254,11 +248,9 @@ void i915_gem_context_init(struct drm_device *dev) dev_priv->ring[RCS].default_context) return; - ctx_size = get_context_size(dev); - dev_priv->hw_context_size = get_context_size(dev); - dev_priv->hw_context_size = round_up(dev_priv->hw_context_size, 4096); + dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); - if (ctx_size <= 0 || ctx_size > (1<<20)) { + if (dev_priv->hw_context_size > (1<<20)) { dev_priv->hw_contexts_disabled = true; return; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index bdaca3f47988..926a1e2dd234 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -725,7 +725,9 @@ static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl) static int gen6_gmch_probe(struct drm_device *dev, size_t *gtt_total, - size_t *stolen) + size_t *stolen, + phys_addr_t *mappable_base, + unsigned long *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; phys_addr_t gtt_bus_addr; @@ -733,11 +735,13 @@ static int gen6_gmch_probe(struct drm_device *dev, u16 snb_gmch_ctl; int ret; + *mappable_base = pci_resource_start(dev->pdev, 2); + *mappable_end = pci_resource_len(dev->pdev, 2); + /* 64/512MB is the current min/max we actually know of, but this is just * a coarse sanity check. */ - if ((dev_priv->gtt.mappable_end < (64<<20) || - (dev_priv->gtt.mappable_end > (512<<20)))) { + if ((*mappable_end < (64<<20) || (*mappable_end > (512<<20)))) { DRM_ERROR("Unknown GMADR size (%lx)\n", dev_priv->gtt.mappable_end); return -ENXIO; @@ -782,7 +786,9 @@ static void gen6_gmch_remove(struct drm_device *dev) static int i915_gmch_probe(struct drm_device *dev, size_t *gtt_total, - size_t *stolen) + size_t *stolen, + phys_addr_t *mappable_base, + unsigned long *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -793,7 +799,7 @@ static int i915_gmch_probe(struct drm_device *dev, return -EIO; } - intel_gtt_get(gtt_total, stolen); + intel_gtt_get(gtt_total, stolen, mappable_base, mappable_end); dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev); dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; @@ -814,9 +820,6 @@ int i915_gem_gtt_init(struct drm_device *dev) unsigned long gtt_size; int ret; - gtt->mappable_base = pci_resource_start(dev->pdev, 2); - gtt->mappable_end = pci_resource_len(dev->pdev, 2); - if (INTEL_INFO(dev)->gen <= 5) { dev_priv->gtt.gtt_probe = i915_gmch_probe; dev_priv->gtt.gtt_remove = i915_gmch_remove; @@ -826,7 +829,9 @@ int i915_gem_gtt_init(struct drm_device *dev) } ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, - &dev_priv->gtt.stolen_size); + &dev_priv->gtt.stolen_size, + >t->mappable_base, + >t->mappable_end); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 13bb8d3f2a77..2cd97d1cc920 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1924,7 +1924,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) * This register is the same on all known PCH chips. */ -static void ironlake_enable_pch_hotplug(struct drm_device *dev) +static void ibx_enable_hotplug(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 hotplug; @@ -1937,6 +1937,28 @@ static void ironlake_enable_pch_hotplug(struct drm_device *dev) I915_WRITE(PCH_PORT_HOTPLUG, hotplug); } +static void ibx_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 mask; + + if (HAS_PCH_IBX(dev)) + mask = SDE_HOTPLUG_MASK | + SDE_GMBUS | + SDE_AUX_MASK; + else + mask = SDE_HOTPLUG_MASK_CPT | + SDE_GMBUS_CPT | + SDE_AUX_MASK_CPT; + + I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + I915_WRITE(SDEIMR, ~mask); + I915_WRITE(SDEIER, mask); + POSTING_READ(SDEIER); + + ibx_enable_hotplug(dev); +} + static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -1945,8 +1967,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | DE_AUX_CHANNEL_A; u32 render_irqs; - u32 hotplug_mask; - u32 pch_irq_mask; dev_priv->irq_mask = ~display_mask; @@ -1974,30 +1994,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); - if (HAS_PCH_CPT(dev)) { - hotplug_mask = (SDE_CRT_HOTPLUG_CPT | - SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | - SDE_PORTD_HOTPLUG_CPT | - SDE_GMBUS_CPT | - SDE_AUX_MASK_CPT); - } else { - hotplug_mask = (SDE_CRT_HOTPLUG | - SDE_PORTB_HOTPLUG | - SDE_PORTC_HOTPLUG | - SDE_PORTD_HOTPLUG | - SDE_GMBUS | - SDE_AUX_MASK); - } - - pch_irq_mask = ~hotplug_mask; - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, pch_irq_mask); - I915_WRITE(SDEIER, hotplug_mask); - POSTING_READ(SDEIER); - - ironlake_enable_pch_hotplug(dev); + ibx_irq_postinstall(dev); if (IS_IRONLAKE_M(dev)) { /* Clear & enable PCU event interrupts */ @@ -2020,8 +2017,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB; u32 render_irqs; - u32 hotplug_mask; - u32 pch_irq_mask; dev_priv->irq_mask = ~display_mask; @@ -2045,20 +2040,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); - hotplug_mask = (SDE_CRT_HOTPLUG_CPT | - SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | - SDE_PORTD_HOTPLUG_CPT | - SDE_GMBUS_CPT | - SDE_AUX_MASK_CPT); - pch_irq_mask = ~hotplug_mask; - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, pch_irq_mask); - I915_WRITE(SDEIER, hotplug_mask); - POSTING_READ(SDEIER); - - ironlake_enable_pch_hotplug(dev); + ibx_irq_postinstall(dev); return 0; } @@ -2137,12 +2119,12 @@ static void valleyview_hpd_irq_setup(struct drm_device *dev) u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); /* Note HDMI and DP share bits */ - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2408,12 +2390,12 @@ static void i915_hpd_irq_setup(struct drm_device *dev) if (I915_HAS_HOTPLUG(dev)) { hotplug_en = I915_READ(PORT_HOTPLUG_EN); - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2642,12 +2624,12 @@ static void i965_hpd_irq_setup(struct drm_device *dev) /* Note HDMI and DP share hotplug bits */ hotplug_en = 0; - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (IS_G4X(dev)) { if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) hotplug_en |= SDVOC_HOTPLUG_INT_EN; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 15f5e7f9cded..527b664d3434 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -308,6 +308,7 @@ #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) +#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) #define PIPE_CONTROL_QW_WRITE (1<<14) @@ -1235,6 +1236,10 @@ #define MAD_DIMM_A_SIZE_SHIFT 0 #define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) +/** snb MCH registers for priority tuning */ +#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10) +#define MCH_SSKPD_WM0_MASK 0x3f +#define MCH_SSKPD_WM0_VAL 0xc /* Clocking configuration register */ #define CLKCFG 0x10c00 @@ -1625,12 +1630,9 @@ /* Hotplug control (945+ only) */ #define PORT_HOTPLUG_EN (dev_priv->info->display_mmio_offset + 0x61110) -#define HDMIB_HOTPLUG_INT_EN (1 << 29) -#define DPB_HOTPLUG_INT_EN (1 << 29) -#define HDMIC_HOTPLUG_INT_EN (1 << 28) -#define DPC_HOTPLUG_INT_EN (1 << 28) -#define HDMID_HOTPLUG_INT_EN (1 << 27) -#define DPD_HOTPLUG_INT_EN (1 << 27) +#define PORTB_HOTPLUG_INT_EN (1 << 29) +#define PORTC_HOTPLUG_INT_EN (1 << 28) +#define PORTD_HOTPLUG_INT_EN (1 << 27) #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) @@ -1653,19 +1655,12 @@ #define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114) /* HDMI/DP bits are gen4+ */ -#define DPB_HOTPLUG_LIVE_STATUS (1 << 29) -#define DPC_HOTPLUG_LIVE_STATUS (1 << 28) -#define DPD_HOTPLUG_LIVE_STATUS (1 << 27) -#define DPD_HOTPLUG_INT_STATUS (3 << 21) -#define DPC_HOTPLUG_INT_STATUS (3 << 19) -#define DPB_HOTPLUG_INT_STATUS (3 << 17) -/* HDMI bits are shared with the DP bits */ -#define HDMIB_HOTPLUG_LIVE_STATUS (1 << 29) -#define HDMIC_HOTPLUG_LIVE_STATUS (1 << 28) -#define HDMID_HOTPLUG_LIVE_STATUS (1 << 27) -#define HDMID_HOTPLUG_INT_STATUS (3 << 21) -#define HDMIC_HOTPLUG_INT_STATUS (3 << 19) -#define HDMIB_HOTPLUG_INT_STATUS (3 << 17) +#define PORTB_HOTPLUG_LIVE_STATUS (1 << 29) +#define PORTC_HOTPLUG_LIVE_STATUS (1 << 28) +#define PORTD_HOTPLUG_LIVE_STATUS (1 << 27) +#define PORTD_HOTPLUG_INT_STATUS (3 << 21) +#define PORTC_HOTPLUG_INT_STATUS (3 << 19) +#define PORTB_HOTPLUG_INT_STATUS (3 << 17) /* CRT/TV common between gen3+ */ #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) @@ -2954,6 +2949,7 @@ #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 #define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_PIPE_CSC_ENABLE (1<<24) #define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) @@ -3015,6 +3011,7 @@ #define DISPPLANE_RGBA888 (0xf<<26) #define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_PIPE_CSC_ENABLE (1<<24) #define DISPPLANE_SEL_PIPE_SHIFT 24 #define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT) #define DISPPLANE_SEL_PIPE_A 0 @@ -3103,6 +3100,7 @@ #define DVS_FORMAT_RGBX101010 (1<<25) #define DVS_FORMAT_RGBX888 (2<<25) #define DVS_FORMAT_RGBX161616 (3<<25) +#define DVS_PIPE_CSC_ENABLE (1<<24) #define DVS_SOURCE_KEY (1<<22) #define DVS_RGB_ORDER_XBGR (1<<20) #define DVS_YUV_BYTE_ORDER_MASK (3<<16) @@ -3170,7 +3168,7 @@ #define SPRITE_FORMAT_RGBX161616 (3<<25) #define SPRITE_FORMAT_YUV444 (4<<25) #define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ -#define SPRITE_CSC_ENABLE (1<<24) +#define SPRITE_PIPE_CSC_ENABLE (1<<24) #define SPRITE_SOURCE_KEY (1<<22) #define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ #define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) @@ -3917,7 +3915,7 @@ #define FDI_10BPC (1<<16) #define FDI_6BPC (2<<16) #define FDI_12BPC (3<<16) -#define FDI_LINK_REVERSE_OVERWRITE (1<<15) +#define FDI_RX_LINK_REVERSAL_OVERRIDE (1<<15) #define FDI_DMI_LINK_REVERSE_MASK (1<<14) #define FDI_RX_PLL_ENABLE (1<<13) #define FDI_FS_ERR_CORRECT_ENABLE (1<<11) @@ -4272,8 +4270,8 @@ #define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 #define GEN6_PCODE_WRITE_RC6VIDS 0x4 #define GEN6_PCODE_READ_RC6VIDS 0x5 -#define GEN6_ENCODE_RC6_VID(mv) (((mv) / 5) - 245) < 0 ?: 0 -#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) > 0 ? ((vids) * 5) + 245 : 0) +#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) +#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) #define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 @@ -4516,6 +4514,7 @@ #define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */ #define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */ #define DDI_BUF_EMP_MASK (0xf<<24) +#define DDI_BUF_PORT_REVERSAL (1<<16) #define DDI_BUF_IS_IDLE (1<<7) #define DDI_A_4_LANES (1<<4) #define DDI_PORT_WIDTH_X1 (0<<1) @@ -4649,4 +4648,51 @@ #define WM_DBG_DISALLOW_MAXFIFO (1<<1) #define WM_DBG_DISALLOW_SPRITE (1<<2) +/* pipe CSC */ +#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 +#define _PIPE_A_CSC_COEFF_BY 0x49014 +#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 +#define _PIPE_A_CSC_COEFF_BU 0x4901c +#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 +#define _PIPE_A_CSC_COEFF_BV 0x49024 +#define _PIPE_A_CSC_MODE 0x49028 +#define _PIPE_A_CSC_PREOFF_HI 0x49030 +#define _PIPE_A_CSC_PREOFF_ME 0x49034 +#define _PIPE_A_CSC_PREOFF_LO 0x49038 +#define _PIPE_A_CSC_POSTOFF_HI 0x49040 +#define _PIPE_A_CSC_POSTOFF_ME 0x49044 +#define _PIPE_A_CSC_POSTOFF_LO 0x49048 + +#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 +#define _PIPE_B_CSC_COEFF_BY 0x49114 +#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 +#define _PIPE_B_CSC_COEFF_BU 0x4911c +#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 +#define _PIPE_B_CSC_COEFF_BV 0x49124 +#define _PIPE_B_CSC_MODE 0x49128 +#define _PIPE_B_CSC_PREOFF_HI 0x49130 +#define _PIPE_B_CSC_PREOFF_ME 0x49134 +#define _PIPE_B_CSC_PREOFF_LO 0x49138 +#define _PIPE_B_CSC_POSTOFF_HI 0x49140 +#define _PIPE_B_CSC_POSTOFF_ME 0x49144 +#define _PIPE_B_CSC_POSTOFF_LO 0x49148 + +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) +#define CSC_MODE_YUV_TO_RGB (1 << 0) + +#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 729dd1a3fe72..969d08c72d10 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -800,10 +800,14 @@ void intel_crt_init(struct drm_device *dev) dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; /* - * TODO: find a proper way to discover whether we need to set the - * polarity reversal bit or not, instead of relying on the BIOS. + * TODO: find a proper way to discover whether we need to set the the + * polarity and link reversal bits or not, instead of relying on the + * BIOS. */ - if (HAS_PCH_LPT(dev)) - dev_priv->fdi_rx_polarity_reversed = - !!(I915_READ(_FDI_RXA_CTL) & FDI_RX_POLARITY_REVERSED_LPT); + if (HAS_PCH_LPT(dev)) { + u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT | + FDI_RX_LINK_REVERSAL_OVERRIDE; + + dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config; + } } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a259e09eb6a8..d64af5aa4a1c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -180,10 +180,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); /* Enable the PCH Receiver FDI PLL */ - rx_ctl_val = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE | - ((intel_crtc->fdi_lanes - 1) << 19); - if (dev_priv->fdi_rx_polarity_reversed) - rx_ctl_val |= FDI_RX_POLARITY_REVERSED_LPT; + rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | + FDI_RX_PLL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 19); I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); udelay(220); @@ -205,7 +203,10 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_ENABLE); - /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */ + /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. + * DDI E does not support port reversal, the functionality is + * achieved on the PCH side in FDI_RX_CTL, so no need to set the + * port reversal bit */ I915_WRITE(DDI_BUF_CTL(PORT_E), DDI_BUF_CTL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 1) | @@ -680,8 +681,11 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, intel_crtc->eld_vld = false; if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); - intel_dp->DP = DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; + intel_dp->DP = intel_dig_port->port_reversal | + DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; switch (intel_dp->lane_count) { case 1: intel_dp->DP |= DDI_PORT_WIDTH_X1; @@ -1304,11 +1308,15 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) uint32_t tmp; if (type == INTEL_OUTPUT_HDMI) { + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); + /* In HDMI/DVI mode, the port width, and swing/emphasis values * are ignored so nothing special needs to be done besides * enabling the port. */ - I915_WRITE(DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE); + I915_WRITE(DDI_BUF_CTL(port), + intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE); } else if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -1485,6 +1493,7 @@ static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { void intel_ddi_init(struct drm_device *dev, enum port port) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_digital_port *intel_dig_port; struct intel_encoder *intel_encoder; struct drm_encoder *encoder; @@ -1525,6 +1534,8 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->get_hw_state = intel_ddi_get_hw_state; intel_dig_port->port = port; + intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & + DDI_BUF_PORT_REVERSAL; if (hdmi_connector) intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); else diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca8d5929063e..6337196b7931 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -154,8 +154,8 @@ static const intel_limit_t intel_limits_i9xx_sdvo = { .vco = { .min = 1400000, .max = 2800000 }, .n = { .min = 1, .max = 6 }, .m = { .min = 70, .max = 120 }, - .m1 = { .min = 10, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, .p = { .min = 5, .max = 80 }, .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 200000, @@ -168,8 +168,8 @@ static const intel_limit_t intel_limits_i9xx_lvds = { .vco = { .min = 1400000, .max = 2800000 }, .n = { .min = 1, .max = 6 }, .m = { .min = 70, .max = 120 }, - .m1 = { .min = 10, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, .p = { .min = 7, .max = 98 }, .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 112000, @@ -2226,12 +2226,6 @@ intel_finish_fb(struct drm_framebuffer *old_fb) bool was_interruptible = dev_priv->mm.interruptible; int ret; - WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); - - wait_event(dev_priv->pending_flip_queue, - i915_reset_in_progress(&dev_priv->gpu_error) || - atomic_read(&obj->pending_flip) == 0); - /* Big Hammer, we also need to ensure that any pending * MI_WAIT_FOR_EVENT inside a user batch buffer on the * current scanout is retired before unpinning the old @@ -2874,10 +2868,12 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); unsigned long flags; bool pending; - if (i915_reset_in_progress(&dev_priv->gpu_error)) + if (i915_reset_in_progress(&dev_priv->gpu_error) || + intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) return false; spin_lock_irqsave(&dev->event_lock, flags); @@ -3615,6 +3611,11 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(dev); intel_enable_pll(dev_priv, pipe); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); @@ -3637,6 +3638,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + u32 pctl; if (!intel_crtc->active) @@ -3656,6 +3658,13 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_disable_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); + + /* Disable pannel fitter if it is on this pipe. */ + pctl = I915_READ(PFIT_CONTROL); + if ((pctl & PFIT_ENABLE) && + ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe) + I915_WRITE(PFIT_CONTROL, 0); + intel_disable_pll(dev_priv, pipe); intel_crtc->active = false; @@ -5109,6 +5118,71 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, POSTING_READ(PIPECONF(pipe)); } +/* + * Set up the pipe CSC unit. + * + * Currently only full range RGB to limited range RGB conversion + * is supported, but eventually this should handle various + * RGB<->YCbCr scenarios as well. + */ +static void intel_set_pipe_csc(struct drm_crtc *crtc, + const struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint16_t coeff = 0x7800; /* 1.0 */ + + /* + * TODO: Check what kind of values actually come out of the pipe + * with these coeff/postoff values and adjust to get the best + * accuracy. Perhaps we even need to take the bpc value into + * consideration. + */ + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */ + + /* + * GY/GU and RY/RU should be the other way around according + * to BSpec, but reality doesn't agree. Just set them up in + * a way that results in the correct picture. + */ + I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16); + I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff); + I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0); + I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16); + + I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0); + + if (INTEL_INFO(dev)->gen > 6) { + uint16_t postoff = 0; + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + postoff = (16 * (1 << 13) / 255) & 0x1fff; + + I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff); + + I915_WRITE(PIPE_CSC_MODE(pipe), 0); + } else { + uint32_t mode = CSC_MODE_YUV_TO_RGB; + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + mode |= CSC_BLACK_SCREEN_OFFSET; + + I915_WRITE(PIPE_CSC_MODE(pipe), mode); + } +} + static void haswell_set_pipeconf(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, bool dither) @@ -5697,8 +5771,10 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, haswell_set_pipeconf(crtc, adjusted_mode, dither); + intel_set_pipe_csc(crtc, adjusted_mode); + /* Set up the display plane register */ - I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); POSTING_READ(DSPCNTR(plane)); ret = intel_pipe_set_base(crtc, x, y, fb); @@ -6103,6 +6179,8 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base) cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); cntl |= CURSOR_MODE_DISABLE; } + if (IS_HASWELL(dev)) + cntl |= CURSOR_PIPE_CSC_ENABLE; I915_WRITE(CURCNTR_IVB(pipe), cntl); intel_crtc->cursor_visible = visible; @@ -7235,6 +7313,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->enable_stall_check = true; atomic_inc(&intel_crtc->unpin_work_count); + intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); ret = dev_priv->display.queue_flip(dev, crtc, fb, obj); if (ret) @@ -7876,7 +7955,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct intel_encoder *encoder; int count, ro; - /* The upper layers ensure that we either disabl a crtc or have a list + /* The upper layers ensure that we either disable a crtc or have a list * of connectors. For paranoia, double-check this. */ WARN_ON(!set->fb && (set->num_connectors != 0)); WARN_ON(set->fb && (set->num_connectors == 0)); @@ -8655,6 +8734,9 @@ static struct intel_quirk intel_quirks[] = { /* Acer/Packard Bell NCL20 */ { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, + + /* Acer Aspire 4736Z */ + { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 13c1536a8bb2..31c0205685ab 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2302,13 +2302,13 @@ g4x_dp_detect(struct intel_dp *intel_dp) switch (intel_dig_port->port) { case PORT_B: - bit = DPB_HOTPLUG_LIVE_STATUS; + bit = PORTB_HOTPLUG_LIVE_STATUS; break; case PORT_C: - bit = DPC_HOTPLUG_LIVE_STATUS; + bit = PORTC_HOTPLUG_LIVE_STATUS; break; case PORT_D: - bit = DPD_HOTPLUG_LIVE_STATUS; + bit = PORTD_HOTPLUG_LIVE_STATUS; break; default: return connector_status_unknown; @@ -2837,15 +2837,15 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, name = "DPDDC-A"; break; case PORT_B: - dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; name = "DPDDC-B"; break; case PORT_C: - dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; name = "DPDDC-C"; break; case PORT_D: - dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; name = "DPDDC-D"; break; default: diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a2ec01c49f40..d282052aadd4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -235,6 +235,9 @@ struct intel_crtc { /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; uint32_t ddi_pll_sel; + + /* reset counter value when the last flip was submitted */ + unsigned int reset_counter; }; struct intel_plane { @@ -390,6 +393,7 @@ struct intel_dp { struct intel_digital_port { struct intel_encoder base; enum port port; + u32 port_reversal; struct intel_dp dp; struct intel_hdmi hdmi; }; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 3883bed80faa..3ea0c8b6a00f 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -802,10 +802,10 @@ static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) switch (intel_dig_port->port) { case PORT_B: - bit = HDMIB_HOTPLUG_LIVE_STATUS; + bit = PORTB_HOTPLUG_LIVE_STATUS; break; case PORT_C: - bit = HDMIC_HOTPLUG_LIVE_STATUS; + bit = PORTC_HOTPLUG_LIVE_STATUS; break; default: bit = 0; @@ -1021,15 +1021,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, switch (port) { case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; break; case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; break; case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; break; case PORT_A: /* Internal port only for eDP. */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index feb43fd7debf..3d1d97488cc9 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -51,7 +51,6 @@ struct intel_lvds_encoder { u32 pfit_control; u32 pfit_pgm_ratios; - bool pfit_dirty; bool is_dual_link; u32 reg; @@ -151,6 +150,29 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) I915_WRITE(lvds_encoder->reg, temp); } +static void intel_pre_enable_lvds(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) + return; + + /* + * Enable automatic panel scaling so that non-native modes + * fill the screen. The panel fitter should only be + * adjusted whilst the pipe is disabled, according to + * register description and PRM. + */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + enc->pfit_control, + enc->pfit_pgm_ratios); + + I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, enc->pfit_control); +} + /** * Sets the power state for the panel. */ @@ -172,22 +194,6 @@ static void intel_enable_lvds(struct intel_encoder *encoder) I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN); - if (lvds_encoder->pfit_dirty) { - /* - * Enable automatic panel scaling so that non-native modes - * fill the screen. The panel fitter should only be - * adjusted whilst the pipe is disabled, according to - * register description and PRM. - */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - lvds_encoder->pfit_control, - lvds_encoder->pfit_pgm_ratios); - - I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control); - lvds_encoder->pfit_dirty = false; - } - I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); POSTING_READ(lvds_encoder->reg); if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000)) @@ -217,11 +223,6 @@ static void intel_disable_lvds(struct intel_encoder *encoder) if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); - if (lvds_encoder->pfit_control) { - I915_WRITE(PFIT_CONTROL, 0); - lvds_encoder->pfit_dirty = true; - } - I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN); POSTING_READ(lvds_encoder->reg); } @@ -461,7 +462,6 @@ out: pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { lvds_encoder->pfit_control = pfit_control; lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; - lvds_encoder->pfit_dirty = true; } dev_priv->lvds_border_bits = border; @@ -547,13 +547,14 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = { }; /* - * Lid events. Note the use of 'modeset_on_lid': - * - we set it on lid close, and reset it on open + * Lid events. Note the use of 'modeset': + * - we set it to MODESET_ON_LID_OPEN on lid close, + * and set it to MODESET_DONE on open * - we use it as a "only once" bit (ie we ignore - * duplicate events where it was already properly - * set/reset) - * - the suspend/resume paths will also set it to - * zero, since they restore the mode ("lid open"). + * duplicate events where it was already properly set) + * - the suspend/resume paths will set it to + * MODESET_SUSPENDED and ignore the lid open event, + * because they restore the mode ("lid open"). */ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, void *unused) @@ -567,6 +568,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, if (dev->switch_power_state != DRM_SWITCH_POWER_ON) return NOTIFY_OK; + mutex_lock(&dev_priv->modeset_restore_lock); + if (dev_priv->modeset_restore == MODESET_SUSPENDED) + goto exit; /* * check and update the status of LVDS connector after receiving * the LID nofication event. @@ -575,21 +579,24 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, /* Don't force modeset on machines where it causes a GPU lockup */ if (dmi_check_system(intel_no_modeset_on_lid)) - return NOTIFY_OK; + goto exit; if (!acpi_lid_open()) { - dev_priv->modeset_on_lid = 1; - return NOTIFY_OK; + /* do modeset on next lid open event */ + dev_priv->modeset_restore = MODESET_ON_LID_OPEN; + goto exit; } - if (!dev_priv->modeset_on_lid) - return NOTIFY_OK; - - dev_priv->modeset_on_lid = 0; + if (dev_priv->modeset_restore == MODESET_DONE) + goto exit; drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, true); drm_modeset_unlock_all(dev); + dev_priv->modeset_restore = MODESET_DONE; + +exit: + mutex_unlock(&dev_priv->modeset_restore_lock); return NOTIFY_OK; } @@ -1093,6 +1100,7 @@ bool intel_lvds_init(struct drm_device *dev) DRM_MODE_ENCODER_LVDS); intel_encoder->enable = intel_enable_lvds; + intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; intel_encoder->disable = intel_disable_lvds; intel_encoder->get_hw_state = intel_lvds_get_hw_state; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index bee8cb6108a7..a3730e0289e5 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -321,6 +321,9 @@ void intel_panel_enable_backlight(struct drm_device *dev, if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); + dev_priv->backlight_enabled = true; + intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); + if (INTEL_INFO(dev)->gen >= 4) { uint32_t reg, tmp; @@ -356,12 +359,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, } set_level: - /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. - * BLC_PWM_CPU_CTL may be cleared to zero automatically when these - * registers are set. + /* Check the current backlight level and try to set again if it's zero. + * On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically + * when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written. */ - dev_priv->backlight_enabled = true; - intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); + if (!intel_panel_get_backlight(dev)) + intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); } static void intel_panel_init_backlight(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7c9a6d11700e..61fee7fcdc2c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2289,7 +2289,6 @@ err_unpin: i915_gem_object_unpin(ctx); err_unref: drm_gem_object_unreference(&ctx->base); - mutex_unlock(&dev->struct_mutex); return NULL; } @@ -3584,6 +3583,19 @@ static void cpt_init_clock_gating(struct drm_device *dev) } } +static void gen6_check_mch_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(MCH_SSKPD); + if ((tmp & MCH_SSKPD_WM0_MASK) != MCH_SSKPD_WM0_VAL) { + DRM_INFO("Wrong MCH_SSKPD value: 0x%08x\n", tmp); + DRM_INFO("This can cause pipe underruns and display issues.\n"); + DRM_INFO("Please upgrade your BIOS to fix this.\n"); + } +} + static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3676,6 +3688,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_GT_MODE_HI)); cpt_init_clock_gating(dev); + + gen6_check_mch_setup(dev); } static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) @@ -3861,6 +3875,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); cpt_init_clock_gating(dev); + + gen6_check_mch_setup(dev); } static void valleyview_init_clock_gating(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 00525ff59045..1d5d613eb6be 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -318,6 +318,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, * TLB invalidate requires a post-sync write. */ flags |= PIPE_CONTROL_QW_WRITE; + flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache @@ -331,7 +332,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4)); intel_ring_emit(ring, flags); - intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, scratch_addr); intel_ring_emit(ring, 0); intel_ring_advance(ring); @@ -467,6 +468,9 @@ init_pipe_control(struct intel_ring_buffer *ring) if (pc->cpu_page == NULL) goto err_unpin; + DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n", + ring->name, pc->gtt_offset); + pc->obj = obj; ring->private = pc; return 0; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f8293061d6bd..d086e48a831a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -50,6 +50,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; sprctl = I915_READ(SPRCTL(pipe)); @@ -89,6 +90,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, sprctl |= SPRITE_TRICKLE_FEED_DISABLE; sprctl |= SPRITE_ENABLE; + if (IS_HASWELL(dev)) + sprctl |= SPRITE_PIPE_CSC_ENABLE; + /* Sizes are 0 based */ src_w--; src_h--; @@ -103,19 +107,15 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, * when scaling is disabled. */ if (crtc_w != src_w || crtc_h != src_h) { - if (!dev_priv->sprite_scaling_enabled) { - dev_priv->sprite_scaling_enabled = true; + dev_priv->sprite_scaling_enabled |= 1 << pipe; + + if (!scaling_was_enabled) { intel_update_watermarks(dev); intel_wait_for_vblank(dev, pipe); } sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - } else { - if (dev_priv->sprite_scaling_enabled) { - dev_priv->sprite_scaling_enabled = false; - /* potentially re-enable LP watermarks */ - intel_update_watermarks(dev); - } - } + } else + dev_priv->sprite_scaling_enabled &= ~(1 << pipe); I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); @@ -141,6 +141,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRCTL(pipe), sprctl); I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); + + /* potentially re-enable LP watermarks */ + if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) + intel_update_watermarks(dev); } static void @@ -150,6 +154,7 @@ ivb_disable_plane(struct drm_plane *plane) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; + bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ @@ -159,8 +164,11 @@ ivb_disable_plane(struct drm_plane *plane) I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); - dev_priv->sprite_scaling_enabled = false; - intel_update_watermarks(dev); + dev_priv->sprite_scaling_enabled &= ~(1 << pipe); + + /* potentially re-enable LP watermarks */ + if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) + intel_update_watermarks(dev); } static int |