diff options
author | Dave Airlie <airlied@redhat.com> | 2013-12-23 10:46:07 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-12-23 10:46:07 +1000 |
commit | 859ae233cd0ee76b6143f948ba1cb6b0b4c342f8 (patch) | |
tree | b2071654cf0ef520e047035720a101d3222e47bc | |
parent | 785e15ecefbfe8ea311ae320fdacd482a84b3cc3 (diff) | |
parent | ab57fff1302c485d74992d34df24ccb5efda244e (diff) | |
download | op-kernel-dev-859ae233cd0ee76b6143f948ba1cb6b0b4c342f8.zip op-kernel-dev-859ae233cd0ee76b6143f948ba1cb6b0b4c342f8.tar.gz |
Merge tag 'drm-intel-next-2013-12-13' of git://people.freedesktop.org/~danvet/drm-intel into drm-next
- fbc1 improvements from Ville (pre-gm45).
- vlv forcewake improvements from Deepak S.
- Some corner-cases fixes from Mika for the context hang stat code.
- pc8 improvements and prep work for runtime D3 from Paulo, almost ready for
primetime.
- gen2 dpll fixes from Ville.
- DSI improvements from Shobhit Kumar.
- A few smaller fixes and improvements all over.
[airlied: intel_ddi.c conflict fixed up]
* tag 'drm-intel-next-2013-12-13' of git://people.freedesktop.org/~danvet/drm-intel: (61 commits)
drm/i915/bdw: Implement ff workarounds
drm/i915/bdw: Force all Data Cache Data Port access to be Non-Coherent
drm/i915/bdw: Don't use forcewake needlessly
drm/i915: Clear out old GT FIFO errors in intel_uncore_early_sanitize()
drm/i915: dont call irq_put when irq test is on
drm/i915: Rework the FBC interval/stall stuff a bit
drm/i915: Enable FBC for all mobile gen2 and gen3 platforms
drm/i915: FBC_CONTROL2 is gen4 only
drm/i915: Gen2 FBC1 CFB pitch wants 32B units
drm/i915: split intel_ddi_pll_mode_set in 2 pieces
drm/i915: Fix timeout with missed interrupts in __wait_seqno
drm/i915: touch VGA MSR after we enable the power well
drm/i915: extract hsw_power_well_post_{enable, disable}
drm/i915: remove i915_disable_vga_mem declaration
drm/i915: Parametrize the dphy and other spec specific parameters
drm/i915: Remove redundant DSI PLL enabling
drm/i915: Reorganize the DSI enable/disable sequence
drm/i915: Try harder to get best m, n, p values with minimal error
drm/i915: Compute dsi_clk from pixel clock
drm/i915: Use FLISDSI interface for band gap reset
...
Conflicts:
drivers/gpu/drm/i915/intel_ddi.c
28 files changed, 947 insertions, 506 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 13accf7..6badc15 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -564,10 +564,12 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for_each_ring(ring, dev_priv, i) i915_ring_seqno_info(m, ring); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -585,6 +587,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) { int i; @@ -711,6 +714,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } i915_ring_seqno_info(m, ring); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -904,9 +908,11 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); crstanddelay = I915_READ16(CRSTANDVID); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f)); @@ -919,7 +925,9 @@ static int i915_cur_delayinfo(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; + int ret = 0; + + intel_runtime_pm_get(dev_priv); flush_delayed_work(&dev_priv->rps.delayed_resume_work); @@ -945,7 +953,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) /* RPSTAT1 is in the GT power well */ ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) - return ret; + goto out; gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); @@ -1033,7 +1041,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_puts(m, "no P-state info available\n"); } - return 0; +out: + intel_runtime_pm_put(dev_priv); + return ret; } static int i915_delayfreq_table(struct seq_file *m, void *unused) @@ -1047,6 +1057,7 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); @@ -1054,6 +1065,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev->struct_mutex); return 0; @@ -1075,12 +1088,14 @@ static int i915_inttoext_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for (i = 1; i <= 32; i++) { inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4); seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1098,11 +1113,13 @@ static int ironlake_drpc_info(struct seq_file *m) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); rgvmodectl = I915_READ(MEMMODECTL); rstdbyctl = I915_READ(RSTDBYCTL); crstandvid = I915_READ16(CRSTANDVID); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? @@ -1166,6 +1183,7 @@ static int gen6_drpc_info(struct seq_file *m) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->uncore.lock); forcewake_count = dev_priv->uncore.forcewake_count; @@ -1191,6 +1209,8 @@ static int gen6_drpc_info(struct seq_file *m) sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); mutex_unlock(&dev_priv->rps.hw_lock); + intel_runtime_pm_put(dev_priv); + seq_printf(m, "Video Turbo Mode: %s\n", yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); seq_printf(m, "HW control enabled: %s\n", @@ -1405,6 +1425,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); @@ -1421,6 +1442,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) ((ia_freq >> 8) & 0xff) * 100); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -1436,8 +1458,10 @@ static int i915_gfxec(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); @@ -1617,6 +1641,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_printf(m, "bit6 swizzle for X-tiling = %s\n", swizzle_string(dev_priv->mm.bit_6_swizzle_x)); @@ -1648,6 +1673,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) seq_printf(m, "DISP_ARB_CTL = 0x%08x\n", I915_READ(DISP_ARB_CTL)); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1708,16 +1734,19 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) gen8_ppgtt_info(m, dev); else if (INTEL_INFO(dev)->gen >= 6) gen6_ppgtt_info(m, dev); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1791,6 +1820,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) u32 psrperf = 0; bool enabled = false; + intel_runtime_pm_get(dev_priv); + seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support)); seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok)); @@ -1803,6 +1834,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) EDP_PSR_PERF_CNT_MASK; seq_printf(m, "Performance_Counter: %u\n", psrperf); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3016,8 +3048,11 @@ i915_cache_sharing_get(void *data, u64 *val) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->dev->struct_mutex); *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT; @@ -3038,6 +3073,7 @@ i915_cache_sharing_set(void *data, u64 val) if (val > 3) return -EINVAL; + intel_runtime_pm_get(dev_priv); DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val); /* Update the cache sharing policy here as well */ @@ -3046,6 +3082,7 @@ i915_cache_sharing_set(void *data, u64 val) snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3061,6 +3098,7 @@ static int i915_forcewake_open(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; + intel_runtime_pm_get(dev_priv); gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); return 0; @@ -3075,6 +3113,7 @@ static int i915_forcewake_release(struct inode *inode, struct file *file) return 0; gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + intel_runtime_pm_put(dev_priv); return 0; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index bf38e99..750918c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -42,6 +42,8 @@ #include <linux/vga_switcheroo.h> #include <linux/slab.h> #include <acpi/video.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) @@ -1667,6 +1669,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_GEN5(dev)) intel_gpu_ips_init(dev_priv); + intel_init_runtime_pm(dev_priv); + return 0; out_power_well: @@ -1706,6 +1710,14 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + ret = i915_gem_suspend(dev); + if (ret) { + DRM_ERROR("failed to idle hardware: %d\n", ret); + return ret; + } + + intel_fini_runtime_pm(dev_priv); + intel_gpu_ips_teardown(); /* The i915.ko module is still not prepared to be loaded when @@ -1719,10 +1731,6 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->mm.inactive_shrinker.scan_objects) unregister_shrinker(&dev_priv->mm.inactive_shrinker); - ret = i915_gem_suspend(dev); - if (ret) - DRM_ERROR("failed to idle hardware: %d\n", ret); - io_mapping_free(dev_priv->gtt.mappable); arch_phys_wc_del(dev_priv->gtt.mtrr); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e570ad7..7451693 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -172,6 +172,7 @@ static const struct intel_device_info intel_i85x_info = { .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; @@ -191,6 +192,7 @@ static const struct intel_device_info intel_i915gm_info = { .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i945g_info = { @@ -203,6 +205,7 @@ static const struct intel_device_info intel_i945gm_info = { .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; @@ -502,6 +505,8 @@ static int i915_drm_freeze(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + intel_runtime_pm_get(dev_priv); + /* ignore lid events during suspend */ mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_SUSPENDED; @@ -688,6 +693,8 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_DONE; mutex_unlock(&dev_priv->modeset_restore_lock); + + intel_runtime_pm_put(dev_priv); return error; } @@ -902,6 +909,38 @@ static int i915_pm_poweroff(struct device *dev) return i915_drm_freeze(drm_dev); } +static int i915_runtime_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_RUNTIME_PM(dev)); + + DRM_DEBUG_KMS("Suspending device\n"); + + dev_priv->pm.suspended = true; + intel_opregion_notify_adapter(dev, PCI_D3cold); + + return 0; +} + +static int i915_runtime_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_RUNTIME_PM(dev)); + + DRM_DEBUG_KMS("Resuming device\n"); + + intel_opregion_notify_adapter(dev, PCI_D0); + dev_priv->pm.suspended = false; + + return 0; +} + static const struct dev_pm_ops i915_pm_ops = { .suspend = i915_pm_suspend, .resume = i915_pm_resume, @@ -909,6 +948,8 @@ static const struct dev_pm_ops i915_pm_ops = { .thaw = i915_pm_thaw, .poweroff = i915_pm_poweroff, .restore = i915_pm_resume, + .runtime_suspend = i915_runtime_suspend, + .runtime_resume = i915_runtime_resume, }; static const struct vm_operations_struct i915_gem_vm_ops = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 780f815..ae2c80c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -323,7 +323,7 @@ struct drm_i915_error_state { u32 instps[I915_NUM_RINGS]; u32 extra_instdone[I915_NUM_INSTDONE_REG]; u32 seqno[I915_NUM_RINGS]; - u64 bbaddr; + u64 bbaddr[I915_NUM_RINGS]; u32 fault_reg[I915_NUM_RINGS]; u32 done_reg; u32 faddr[I915_NUM_RINGS]; @@ -372,7 +372,7 @@ struct dpll; struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); - void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); + void (*enable_fbc)(struct drm_crtc *crtc); void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); @@ -695,7 +695,6 @@ struct i915_fbc { struct delayed_work work; struct drm_crtc *crtc; struct drm_framebuffer *fb; - int interval; } *fbc_work; enum no_fbc_reason { @@ -1289,6 +1288,10 @@ struct i915_package_c8 { } regsave; }; +struct i915_runtime_pm { + bool suspended; +}; + enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_NONE, INTEL_PIPE_CRC_SOURCE_PLANE1, @@ -1519,6 +1522,8 @@ typedef struct drm_i915_private { struct i915_package_c8 pc8; + struct i915_runtime_pm pm; + /* Old dri1 support infrastructure, beware the dragons ya fools entering * here! */ struct i915_dri1_state dri1; @@ -1843,6 +1848,7 @@ struct drm_i915_file_private { #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #define HAS_PC8(dev) (IS_HASWELL(dev)) /* XXX HSW:ULX */ +#define HAS_RUNTIME_PM(dev) false #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 @@ -2468,6 +2474,8 @@ u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, enum intel_sbi_destination destination); void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, enum intel_sbi_destination destination); +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg); +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 182c521..2be904c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1015,9 +1015,11 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, struct drm_i915_file_private *file_priv) { drm_i915_private_t *dev_priv = ring->dev->dev_private; + const bool irq_test_in_progress = + ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); struct timespec before, now; DEFINE_WAIT(wait); - long timeout_jiffies; + unsigned long timeout_expire; int ret; WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n"); @@ -1025,7 +1027,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) return 0; - timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 1; + timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { gen6_rps_boost(dev_priv); @@ -1035,8 +1037,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, msecs_to_jiffies(100)); } - if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)) && - WARN_ON(!ring->irq_get(ring))) + if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring))) return -ENODEV; /* Record current time in case interrupted by signal, or wedged */ @@ -1044,7 +1045,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, getrawmonotonic(&before); for (;;) { struct timer_list timer; - unsigned long expire; prepare_to_wait(&ring->irq_queue, &wait, interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); @@ -1070,23 +1070,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, break; } - if (timeout_jiffies <= 0) { + if (timeout && time_after_eq(jiffies, timeout_expire)) { ret = -ETIME; break; } timer.function = NULL; if (timeout || missed_irq(dev_priv, ring)) { + unsigned long expire; + setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); - expire = jiffies + (missed_irq(dev_priv, ring) ? 1: timeout_jiffies); + expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire; mod_timer(&timer, expire); } io_schedule(); - if (timeout) - timeout_jiffies = expire - jiffies; - if (timer.function) { del_singleshot_timer_sync(&timer); destroy_timer_on_stack(&timer); @@ -1095,7 +1094,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, getrawmonotonic(&now); trace_i915_gem_request_wait_end(ring, seqno); - ring->irq_put(ring); + if (!irq_test_in_progress) + ring->irq_put(ring); finish_wait(&ring->irq_queue, &wait); @@ -1380,6 +1380,8 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int ret = 0; bool write = !!(vmf->flags & FAULT_FLAG_WRITE); + intel_runtime_pm_get(dev_priv); + /* We don't use vmf->pgoff since that has the fake offset */ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; @@ -1427,8 +1429,10 @@ out: /* If this -EIO is due to a gpu hang, give the reset code a * chance to clean up the mess. Otherwise return the proper * SIGBUS. */ - if (i915_terminally_wedged(&dev_priv->gpu_error)) - return VM_FAULT_SIGBUS; + if (i915_terminally_wedged(&dev_priv->gpu_error)) { + ret = VM_FAULT_SIGBUS; + break; + } case -EAGAIN: /* * EAGAIN means the gpu is hung and we'll wait for the error @@ -1443,15 +1447,22 @@ out: * EBUSY is ok: this just means that another thread * already did the job. */ - return VM_FAULT_NOPAGE; + ret = VM_FAULT_NOPAGE; + break; case -ENOMEM: - return VM_FAULT_OOM; + ret = VM_FAULT_OOM; + break; case -ENOSPC: - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + break; default: WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret); - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + break; } + + intel_runtime_pm_put(dev_priv); + return ret; } /** @@ -2746,7 +2757,6 @@ int i915_vma_unbind(struct i915_vma *vma) obj->has_aliasing_ppgtt_mapping = 0; } i915_gem_gtt_finish_object(obj); - i915_gem_object_unpin_pages(obj); list_del(&vma->mm_list); /* Avoid an unnecessary call to unbind on rebind. */ @@ -2754,7 +2764,6 @@ int i915_vma_unbind(struct i915_vma *vma) obj->map_and_fenceable = true; drm_mm_remove_node(&vma->node); - i915_gem_vma_destroy(vma); /* Since the unbound list is global, only move to that list if @@ -2762,6 +2771,12 @@ int i915_vma_unbind(struct i915_vma *vma) if (list_empty(&obj->vma_list)) list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list); + /* And finally now the object is completely decoupled from this vma, + * we can drop its hold on the backing storage and allow it to be + * reaped by the shrinker. + */ + i915_gem_object_unpin_pages(obj); + return 0; } @@ -4165,6 +4180,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) drm_i915_private_t *dev_priv = dev->dev_private; struct i915_vma *vma, *next; + intel_runtime_pm_get(dev_priv); + trace_i915_gem_object_destroy(obj); if (obj->phys_obj) @@ -4209,6 +4226,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) kfree(obj->bit_17); i915_gem_object_free(obj); + + intel_runtime_pm_put(dev_priv); } struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3c90dd1..87652fa 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -888,6 +888,24 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, return 0; } +static int +i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, + const u32 ctx_id) +{ + struct i915_ctx_hang_stats *hs; + + hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); + if (IS_ERR(hs)) + return PTR_ERR(hs); + + if (hs->banned) { + DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id); + return -EIO; + } + + return 0; +} + static void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_ring_buffer *ring) @@ -967,8 +985,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; - struct i915_ctx_hang_stats *hs; - u32 ctx_id = i915_execbuffer2_get_context_id(*args); + const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; u32 mask, flags; int ret, mode, i; @@ -1095,6 +1112,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } } + intel_runtime_pm_get(dev_priv); + ret = i915_mutex_lock_interruptible(dev); if (ret) goto pre_mutex_err; @@ -1105,6 +1124,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } + ret = i915_gem_validate_context(dev, file, ctx_id); + if (ret) { + mutex_unlock(&dev->struct_mutex); + goto pre_mutex_err; + } + eb = eb_create(args); if (eb == NULL) { mutex_unlock(&dev->struct_mutex); @@ -1157,17 +1182,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); - if (IS_ERR(hs)) { - ret = PTR_ERR(hs); - goto err; - } - - if (hs->banned) { - ret = -EIO; - goto err; - } - ret = i915_switch_context(ring, file, ctx_id); if (ret) goto err; @@ -1229,6 +1243,10 @@ err: pre_mutex_err: kfree(cliprects); + + /* intel_gpu_busy should also get a ref, so it will free when the device + * is really idle. */ + intel_runtime_pm_put(dev_priv); return ret; } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 79dcb8f..a707cca 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -247,12 +247,11 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); - if (ring == RCS && INTEL_INFO(dev)->gen >= 4) - err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); - if (INTEL_INFO(dev)->gen >= 4) + if (INTEL_INFO(dev)->gen >= 4) { + err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr[ring]); err_printf(m, " BB_STATE: 0x%08x\n", error->bbstate[ring]); - if (INTEL_INFO(dev)->gen >= 4) err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + } err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); if (INTEL_INFO(dev)->gen >= 6) { @@ -725,8 +724,9 @@ static void i915_record_ring_state(struct drm_device *dev, error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); - if (ring->id == RCS) - error->bbaddr = I915_READ64(BB_ADDR); + error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base)); + if (INTEL_INFO(dev)->gen >= 8) + error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32; error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base)); } else { error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2715600..1d44c79 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3139,10 +3139,10 @@ static int i8xx_irq_postinstall(struct drm_device *dev) * Returns true when a page flip has completed. */ static bool i8xx_handle_vblank(struct drm_device *dev, - int pipe, u16 iir) + int plane, int pipe, u32 iir) { drm_i915_private_t *dev_priv = dev->dev_private; - u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); + u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); if (!drm_handle_vblank(dev, pipe)) return false; @@ -3150,7 +3150,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev, if ((iir & flip_pending) == 0) return false; - intel_prepare_page_flip(dev, pipe); + intel_prepare_page_flip(dev, plane); /* We detect FlipDone by looking for the change in PendingFlip from '1' * to '0' on the following vblank, i.e. IIR has the Pendingflip @@ -3219,9 +3219,13 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) notify_ring(dev, &dev_priv->ring[RCS]); for_each_pipe(pipe) { + int plane = pipe; + if (IS_MOBILE(dev)) + plane = !plane; + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && - i8xx_handle_vblank(dev, pipe, iir)) - flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); + i8xx_handle_vblank(dev, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); @@ -3896,8 +3900,8 @@ void hsw_pc8_disable_interrupts(struct drm_device *dev) dev_priv->pc8.regsave.gtier = I915_READ(GTIER); dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); - ironlake_disable_display_irq(dev_priv, ~DE_PCH_EVENT_IVB); - ibx_disable_display_interrupt(dev_priv, ~SDE_HOTPLUG_MASK_CPT); + ironlake_disable_display_irq(dev_priv, 0xffffffff); + ibx_disable_display_interrupt(dev_priv, 0xffffffff); ilk_disable_gt_irq(dev_priv, 0xffffffff); snb_disable_pm_irq(dev_priv, 0xffffffff); @@ -3911,34 +3915,26 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; - uint32_t val, expected; + uint32_t val; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); val = I915_READ(DEIMR); - expected = ~DE_PCH_EVENT_IVB; - WARN(val != expected, "DEIMR is 0x%08x, not 0x%08x\n", val, expected); + WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); - val = I915_READ(SDEIMR) & ~SDE_HOTPLUG_MASK_CPT; - expected = ~SDE_HOTPLUG_MASK_CPT; - WARN(val != expected, "SDEIMR non-HPD bits are 0x%08x, not 0x%08x\n", - val, expected); + val = I915_READ(SDEIMR); + WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); val = I915_READ(GTIMR); - expected = 0xffffffff; - WARN(val != expected, "GTIMR is 0x%08x, not 0x%08x\n", val, expected); + WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); val = I915_READ(GEN6_PMIMR); - expected = 0xffffffff; - WARN(val != expected, "GEN6_PMIMR is 0x%08x, not 0x%08x\n", val, - expected); + WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val); dev_priv->pc8.irqs_disabled = false; ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr); - ibx_enable_display_interrupt(dev_priv, - ~dev_priv->pc8.regsave.sdeimr & - ~SDE_HOTPLUG_MASK_CPT); + ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr); ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr); snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr); I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3be449d..f1eece4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -362,6 +362,7 @@ #define IOSF_PORT_CCK 0x14 #define IOSF_PORT_CCU 0xA9 #define IOSF_PORT_GPS_CORE 0x48 +#define IOSF_PORT_FLISDSI 0x1B #define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) @@ -734,6 +735,8 @@ #define HWSTAM 0x02098 #define DMA_FADD_I8XX 0x020d0 #define RING_BBSTATE(base) ((base)+0x110) +#define RING_BBADDR(base) ((base)+0x140) +#define RING_BBADDR_UDW(base) ((base)+0x168) /* gen8+ */ #define ERROR_GEN6 0x040a0 #define GEN7_ERR_INT 0x44040 @@ -924,7 +927,6 @@ #define CM0_COLOR_EVICT_DISABLE (1<<3) #define CM0_DEPTH_WRITE_DISABLE (1<<1) #define CM0_RC_OP_FLUSH_DISABLE (1<<0) -#define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ #define GFX_FLSH_CNTL_GEN6 0x101008 #define GFX_FLSH_CNTL_EN (1<<0) @@ -1001,6 +1003,7 @@ #define GEN7_FF_THREAD_MODE 0x20a0 #define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN8_FF_DS_REF_CNT_FFME (1 << 19) #define GEN7_FF_TS_SCHED_HS1 (0x5<<16) #define GEN7_FF_TS_SCHED_HS0 (0x3<<16) #define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) @@ -1028,14 +1031,14 @@ #define FBC_CTL_UNCOMPRESSIBLE (1<<14) #define FBC_CTL_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) -#define FBC_CTL_FENCENO (1<<0) +#define FBC_CTL_FENCENO_SHIFT (0) #define FBC_COMMAND 0x0320c #define FBC_CMD_COMPRESS (1<<0) #define FBC_STATUS 0x03210 #define FBC_STAT_COMPRESSING (1<<31) #define FBC_STAT_COMPRESSED (1<<30) #define FBC_STAT_MODIFIED (1<<29) -#define FBC_STAT_CURRENT_LINE (1<<0) +#define FBC_STAT_CURRENT_LINE_SHIFT (0) #define FBC_CONTROL2 0x03214 #define FBC_CTL_FENCE_DBL (0<<4) #define FBC_CTL_IDLE_IMM (0<<2) @@ -4165,6 +4168,10 @@ #define GEN7_L3SQCREG4 0xb034 #define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) +/* GEN8 chicken */ +#define HDC_CHICKEN0 0x7300 +#define HDC_FORCE_NON_COHERENT (1<<4) + /* WaCatErrorRejectionIssue */ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 05d8b16..33bcae3 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -40,10 +40,13 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) struct drm_i915_private *dev_priv = dev->dev_private; u64 raw_time; /* 32b value may overflow during fixed point math */ u64 units = 128ULL, div = 100000ULL, bias = 100ULL; + u32 ret; if (!intel_enable_rc6(dev)) return 0; + intel_runtime_pm_get(dev_priv); + /* On VLV, residency time is in CZ units rather than 1.28us */ if (IS_VALLEYVIEW(dev)) { u32 clkctl2; @@ -52,7 +55,8 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) CLK_CTL2_CZCOUNT_30NS_SHIFT; if (!clkctl2) { WARN(!clkctl2, "bogus CZ count value"); - return 0; + ret = 0; + goto out; } units = DIV_ROUND_UP_ULL(30ULL * bias, (u64)clkctl2); if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) @@ -62,7 +66,11 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) } raw_time = I915_READ(reg) * units; - return DIV_ROUND_UP_ULL(raw_time, div); + ret = DIV_ROUND_UP_ULL(raw_time, div); + +out: + intel_runtime_pm_put(dev_priv); + return ret; } static ssize_t @@ -448,7 +456,9 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); if (attr == &dev_attr_gt_RP0_freq_mhz) { diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index e4fba39..f88e507 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -327,12 +327,12 @@ static int intel_bios_ssc_frequency(struct drm_device *dev, { switch (INTEL_INFO(dev)->gen) { case 2: - return alternate ? 66 : 48; + return alternate ? 66667 : 48000; case 3: case 4: - return alternate ? 100 : 96; + return alternate ? 100000 : 96000; default: - return alternate ? 100 : 120; + return alternate ? 100000 : 120000; } } @@ -796,7 +796,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) */ dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, !HAS_PCH_SPLIT(dev)); - DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); + DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); for (port = PORT_A; port < I915_MAX_PORTS; port++) { struct ddi_vbt_port_info *info = diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index f580a2b..81ed58c 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -39,7 +39,7 @@ struct vbt_header { u8 reserved0; u32 bdb_offset; /**< from beginning of VBT */ u32 aim_offset[4]; /**< from beginning of VBT */ -} __attribute__((packed)); +} __packed; struct bdb_header { u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ @@ -65,7 +65,7 @@ struct vbios_data { u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; u8 rsvd5; /* is crt already on ddc2 */ -} __attribute__((packed)); +} __packed; /* * There are several types of BIOS data blocks (BDBs), each block has @@ -142,7 +142,7 @@ struct bdb_general_features { u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ u8 rsvd11:3; /* finish byte */ -} __attribute__((packed)); +} __packed; /* pre-915 */ #define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ @@ -225,7 +225,7 @@ struct old_child_dev_config { u8 dvo2_wiring; u16 extended_type; u8 dvo_function; -} __attribute__((packed)); +} __packed; /* This one contains field offsets that are known to be common for all BDB * versions. Notice that the meaning of the contents contents may still change, @@ -238,7 +238,7 @@ struct common_child_dev_config { u8 not_common2[2]; u8 ddc_pin; u16 edid_ptr; -} __attribute__((packed)); +} __packed; /* This field changes depending on the BDB version, so the most reliable way to * read it is by checking the BDB version and reading the raw pointer. */ @@ -279,7 +279,7 @@ struct bdb_general_definitions { * sizeof(child_device_config); */ union child_device_config devices[0]; -} __attribute__((packed)); +} __packed; struct bdb_lvds_options { u8 panel_type; @@ -293,7 +293,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; -} __attribute__((packed)); +} __packed; /* LFP pointer table contains entries to the struct below */ struct bdb_lvds_lfp_data_ptr { @@ -303,12 +303,12 @@ struct bdb_lvds_lfp_data_ptr { u8 dvo_table_size; u16 panel_pnp_id_offset; u8 pnp_table_size; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct bdb_lvds_lfp_data_ptr ptr[16]; -} __attribute__((packed)); +} __packed; /* LFP data has 3 blocks per entry */ struct lvds_fp_timing { @@ -325,7 +325,7 @@ struct lvds_fp_timing { u32 pfit_reg; u32 pfit_reg_val; u16 terminator; -} __attribute__((packed)); +} __packed; struct lvds_dvo_timing { u16 clock; /**< In 10khz */ @@ -353,7 +353,7 @@ struct lvds_dvo_timing { u8 vsync_positive:1; u8 hsync_positive:1; u8 rsvd2:1; -} __attribute__((packed)); +} __packed; struct lvds_pnp_id { u16 mfg_name; @@ -361,17 +361,17 @@ struct lvds_pnp_id { u32 serial; u8 mfg_week; u8 mfg_year; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_entry { struct lvds_fp_timing fp_timing; struct lvds_dvo_timing dvo_timing; struct lvds_pnp_id pnp_id; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; -} __attribute__((packed)); +} __packed; struct aimdb_header { char signature[16]; @@ -379,12 +379,12 @@ struct aimdb_header { u16 aimdb_version; u16 aimdb_header_size; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct aimdb_block { u8 aimdb_id; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct vch_panel_data { u16 fp_timing_offset; @@ -395,12 +395,12 @@ struct vch_panel_data { u8 text_fitting_size; u16 graphics_fitting_offset; u8 graphics_fitting_size; -} __attribute__((packed)); +} __packed; struct vch_bdb_22 { struct aimdb_block aimdb_block; struct vch_panel_data panels[16]; -} __attribute__((packed)); +} __packed; struct bdb_sdvo_lvds_options { u8 panel_backlight; @@ -416,7 +416,7 @@ struct bdb_sdvo_lvds_options { u8 panel_misc_bits_2; u8 panel_misc_bits_3; u8 panel_misc_bits_4; -} __attribute__((packed)); +} __packed; #define BDB_DRIVER_FEATURE_NO_LVDS 0 @@ -462,7 +462,7 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; -} __attribute__((packed)); +} __packed; #define EDP_18BPP 0 #define EDP_24BPP 1 @@ -487,14 +487,14 @@ struct edp_power_seq { u16 t9; u16 t10; u16 t11_t12; -} __attribute__ ((packed)); +} __packed; struct edp_link_params { u8 rate:4; u8 lanes:4; u8 preemphasis:4; u8 vswing:4; -} __attribute__ ((packed)); +} __packed; struct bdb_edp { struct edp_power_seq power_seqs[16]; @@ -505,7 +505,7 @@ struct bdb_edp { /* ith bit indicates enabled/disabled for (i+1)th panel */ u16 edp_s3d_feature; u16 edp_t3_optimization; -} __attribute__ ((packed)); +} __packed; void intel_setup_bios(struct drm_device *dev); int intel_parse_bios(struct drm_device *dev); @@ -733,6 +733,6 @@ struct bdb_mipi { u32 hl_switch_cnt; u32 lp_byte_clk; u32 clk_lane_switch_cnt; -} __attribute__((packed)); +} __packed; #endif /* _I830_BIOS_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c8382f5..d7d2683 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -73,7 +73,7 @@ static const u32 hsw_ddi_translations_hdmi[] = { }; static const u32 bdw_ddi_translations_edp[] = { - 0x00FFFFFF, 0x00000012, /* DP parameters */ + 0x00FFFFFF, 0x00000012, /* eDP parameters */ 0x00EBAFFF, 0x00020011, 0x00C71FFF, 0x0006000F, 0x00FFFFFF, 0x00020011, @@ -696,21 +696,23 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, *n2_out = best.n2; *p_out = best.p; *r2_out = best.r2; - - DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n", - clock, *p_out, *n2_out, *r2_out); } -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) +/* + * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and + * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to + * steal the selected PLL. You need to call intel_ddi_pll_enable to actually + * enable the PLL. + */ +bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_crtc *crtc = &intel_crtc->base; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); struct drm_encoder *encoder = &intel_encoder->base; struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_ddi_plls *plls = &dev_priv->ddi_plls; int type = intel_encoder->type; enum pipe pipe = intel_crtc->pipe; - uint32_t reg, val; int clock = intel_crtc->config.port_clock; intel_ddi_put_crtc_pll(crtc); @@ -734,10 +736,8 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) return false; } - /* We don't need to turn any PLL on because we'll use LCPLL. */ - return true; - } else if (type == INTEL_OUTPUT_HDMI) { + uint32_t reg, val; unsigned p, n2, r2; intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); @@ -767,6 +767,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) return false; } + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, p, n2, r2); + if (reg == WRPLL_CTL1) { plls->wrpll1_refcount++; intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; @@ -780,29 +783,98 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) DRM_DEBUG_KMS("Using SPLL on pipe %c\n", pipe_name(pipe)); plls->spll_refcount++; - reg = SPLL_CTL; intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; } else { DRM_ERROR("SPLL already in use\n"); return false; } - WARN(I915_READ(reg) & SPLL_PLL_ENABLE, - "SPLL already enabled\n"); - - val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC; - } else { WARN(1, "Invalid DDI encoder type %d\n", type); return false; } - I915_WRITE(reg, val); - udelay(20); - return true; } +/* + * To be called after intel_ddi_pll_select(). That one selects the PLL to be + * used, this one actually enables the PLL. + */ +void intel_ddi_pll_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int clock = crtc->config.port_clock; + uint32_t reg, cur_val, new_val; + int refcount; + const char *pll_name; + uint32_t enable_bit = (1 << 31); + unsigned int p, n2, r2; + + BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE); + BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE); + + switch (crtc->ddi_pll_sel) { + case PORT_CLK_SEL_LCPLL_2700: + case PORT_CLK_SEL_LCPLL_1350: + case PORT_CLK_SEL_LCPLL_810: + /* + * LCPLL should always be enabled at this point of the mode set + * sequence, so nothing to do. + */ + return; + + case PORT_CLK_SEL_SPLL: + pll_name = "SPLL"; + reg = SPLL_CTL; + refcount = plls->spll_refcount; + new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | + SPLL_PLL_SSC; + break; + + case PORT_CLK_SEL_WRPLL1: + case PORT_CLK_SEL_WRPLL2: + if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) { + pll_name = "WRPLL1"; + reg = WRPLL_CTL1; + refcount = plls->wrpll1_refcount; + } else { + pll_name = "WRPLL2"; + reg = WRPLL_CTL2; + refcount = plls->wrpll2_refcount; + } + + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | + WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); + + break; + + case PORT_CLK_SEL_NONE: + WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n"); + return; + default: + WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel); + return; + } + + cur_val = I915_READ(reg); + + WARN(refcount < 1, "Bad %s refcount: %d\n", pll_name, refcount); + if (refcount == 1) { + WARN(cur_val & enable_bit, "%s already enabled\n", pll_name); + I915_WRITE(reg, new_val); + POSTING_READ(reg); + udelay(20); + } else { + WARN((cur_val & enable_bit) == 0, "%s disabled\n", pll_name); + } +} + void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; @@ -1122,9 +1194,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_panel_on(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, true); } WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); @@ -1167,7 +1237,6 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); ironlake_edp_panel_off(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bb3d6d..72a83fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -90,8 +90,8 @@ intel_fdi_link_freq(struct drm_device *dev) static const intel_limit_t intel_limits_i8xx_dac = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -103,8 +103,8 @@ static const intel_limit_t intel_limits_i8xx_dac = { static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -116,8 +116,8 @@ static const intel_limit_t intel_limits_i8xx_dvo = { static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -329,6 +329,8 @@ static void vlv_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -430,6 +432,8 @@ static void pineview_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -443,6 +447,8 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -1361,6 +1367,10 @@ static void intel_init_dpio(struct drm_device *dev) if (!IS_VALLEYVIEW(dev)) return; + /* Enable the CRI clock source so we can get at the display */ + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_INTEGRATED_CRI_CLK_VLV); + DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; /* * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - @@ -4751,9 +4761,8 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) refclk = 100000; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - refclk = dev_priv->vbt.lvds_ssc_freq * 1000; - DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", - refclk / 1000); + refclk = dev_priv->vbt.lvds_ssc_freq; + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk); } else if (!IS_GEN2(dev)) { refclk = 96000; } else { @@ -5899,9 +5908,9 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) } if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", dev_priv->vbt.lvds_ssc_freq); - return dev_priv->vbt.lvds_ssc_freq * 1000; + return dev_priv->vbt.lvds_ssc_freq; } return 120000; @@ -6163,7 +6172,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, factor = 21; if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && - dev_priv->vbt.lvds_ssc_freq == 100) || + dev_priv->vbt.lvds_ssc_freq == 100000) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (intel_crtc->config.sdvo_tv_clock) @@ -6484,7 +6493,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) uint32_t val; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) - WARN(crtc->base.enabled, "CRTC for pipe %c enabled\n", + WARN(crtc->active, "CRTC for pipe %c enabled\n", pipe_name(crtc->pipe)); WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); @@ -6504,7 +6513,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); val = I915_READ(DEIMR); - WARN((val & ~DE_PCH_EVENT_IVB) != val, + WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff, "Unexpected DEIMR bits enabled: 0x%x\n", val); val = I915_READ(SDEIMR); WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff, @@ -6628,6 +6637,8 @@ void hsw_enable_pc8_work(struct work_struct *__work) struct drm_device *dev = dev_priv->dev; uint32_t val; + WARN_ON(!HAS_PC8(dev)); + if (dev_priv->pc8.enabled) return; @@ -6644,6 +6655,8 @@ void hsw_enable_pc8_work(struct work_struct *__work) lpt_disable_clkout_dp(dev); hsw_pc8_disable_interrupts(dev); hsw_disable_lcpll(dev_priv, true, true); + + intel_runtime_pm_put(dev_priv); } static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv) @@ -6673,12 +6686,16 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv) if (dev_priv->pc8.disable_count != 1) return; + WARN_ON(!HAS_PC8(dev)); + cancel_delayed_work_sync(&dev_priv->pc8.enable_work); if (!dev_priv->pc8.enabled) return; DRM_DEBUG_KMS("Disabling package C8+\n"); + intel_runtime_pm_get(dev_priv); + hsw_restore_lcpll(dev_priv); hsw_pc8_restore_interrupts(dev); lpt_init_pch_refclk(dev); @@ -6885,8 +6902,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int ret; - if (!intel_ddi_pll_mode_set(crtc)) + if (!intel_ddi_pll_select(intel_crtc)) return -EINVAL; + intel_ddi_pll_enable(intel_crtc); if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); @@ -7870,7 +7888,7 @@ static int i9xx_pll_refclk(struct drm_device *dev, u32 dpll = pipe_config->dpll_hw_state.dpll; if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) - return dev_priv->vbt.lvds_ssc_freq * 1000; + return dev_priv->vbt.lvds_ssc_freq; else if (HAS_PCH_SPLIT(dev)) return 120000; else if (!IS_GEN2(dev)) @@ -7933,12 +7951,17 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, else i9xx_clock(refclk, &clock); } else { - bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); + u32 lvds = I915_READ(LVDS); + bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN); if (is_lvds) { clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> DPLL_FPA01_P1_POST_DIV_SHIFT); - clock.p2 = 14; + + if (lvds & LVDS_CLKB_POWER_UP) + clock.p2 = 7; + else + clock.p2 = 14; } else { if (dpll & PLL_P1_DIVIDE_BY_TWO) clock.p1 = 2; @@ -10122,10 +10145,13 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->lut_b[i] = i; } - /* Swap pipes & planes for FBC on pre-965 */ + /* + * On gen2/3 only plane A can do fbc, but the panel fitter and lvds port + * is hooked to plane B. Hence we want plane A feeding pipe B. + */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - if (IS_MOBILE(dev) && IS_GEN3(dev)) { + if (IS_MOBILE(dev) && INTEL_INFO(dev)->gen < 4) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; } @@ -10779,17 +10805,10 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - intel_prepare_ddi(dev); intel_init_clock_gating(dev); - /* Enable the CRI clock source so we can get at the display */ - if (IS_VALLEYVIEW(dev)) - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | - DPLL_INTEGRATED_CRI_CLK_VLV); - intel_init_dpio(dev); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 36f13c5..7df5085 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1038,6 +1038,8 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); } + + DRM_DEBUG_KMS("Wait complete\n"); } static void ironlake_wait_panel_on(struct intel_dp *intel_dp) @@ -1093,6 +1095,8 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) if (ironlake_edp_have_panel_vdd(intel_dp)) return; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("Turning eDP VDD on\n"); if (!ironlake_edp_have_panel_power(intel_dp)) @@ -1141,7 +1145,11 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) /* Make sure sequencer is idle before allowing subsequent activity */ DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); - msleep(intel_dp->panel_power_down_delay); + + if ((pp & POWER_TARGET_ON) == 0) + msleep(intel_dp->panel_power_cycle_delay); + + intel_runtime_pm_put(dev_priv); } } @@ -1234,20 +1242,16 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); - WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); - pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some * panels get very unhappy and cease to work. */ - pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); pp_ctrl_reg = _pp_ctrl_reg(intel_dp); I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - intel_dp->want_panel_vdd = false; - ironlake_wait_panel_off(intel_dp); } @@ -1773,7 +1777,6 @@ static void intel_disable_dp(struct intel_encoder *encoder) /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); ironlake_edp_panel_off(intel_dp); @@ -1942,18 +1945,6 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ DP_LINK_STATUS_SIZE); } -#if 0 -static char *voltage_names[] = { - "0.4V", "0.6V", "0.8V", "1.2V" -}; -static char *pre_emph_names[] = { - "0dB", "3.5dB", "6dB", "9.5dB" -}; -static char *link_train_names[] = { - "pattern 1", "pattern 2", "idle", "off" -}; -#endif - /* * These are source-specific values; current Intel hardware supports * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB @@ -3083,9 +3074,12 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; enum drm_connector_status status; struct edid *edid = NULL; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); @@ -3097,7 +3091,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = g4x_dp_detect(intel_dp); if (status != connector_status_connected) - return status; + goto out; intel_dp_probe_oui(intel_dp); @@ -3113,7 +3107,11 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (intel_encoder->type != INTEL_OUTPUT_EDP) intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; - return connector_status_connected; + status = connector_status_connected; + +out: + intel_runtime_pm_put(dev_priv); + return status; } static int intel_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2b5bcb6..ea00068 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -155,6 +155,7 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; + struct drm_display_mode *downclock_mode; int fitting_mode; /* backlight */ @@ -454,7 +455,7 @@ struct intel_hdmi { bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len); + const void *frame, ssize_t len); void (*set_infoframes)(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); }; @@ -612,7 +613,8 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); void intel_ddi_setup_hw_pll_state(struct drm_device *dev); -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc); +bool intel_ddi_pll_select(struct intel_crtc *crtc); +void intel_ddi_pll_enable(struct intel_crtc *crtc); void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); @@ -702,7 +704,6 @@ void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, int dotclock); bool intel_crtc_active(struct drm_crtc *crtc); -void i915_disable_vga_mem(struct drm_device *dev); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); void intel_display_set_init_power(struct drm_device *dev, bool enable); @@ -823,7 +824,10 @@ void intel_panel_disable_backlight(struct intel_connector *connector); void intel_panel_destroy_backlight(struct drm_connector *connector); void intel_panel_init_backlight_funcs(struct drm_device *dev); enum drm_connector_status intel_panel_detect(struct drm_device *dev); - +extern struct drm_display_mode *intel_find_panel_downclock( + struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector); /* intel_pm.c */ void intel_init_clock_gating(struct drm_device *dev); @@ -858,6 +862,10 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); +void intel_runtime_pm_get(struct drm_i915_private *dev_priv); +void intel_runtime_pm_put(struct drm_i915_private *dev_priv); +void intel_init_runtime_pm(struct drm_i915_private *dev_priv); +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 7b9b350..fabbf0d 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -37,49 +37,18 @@ static const struct intel_dsi_device intel_dsi_devices[] = { }; - -static void vlv_cck_modify(struct drm_i915_private *dev_priv, u32 reg, u32 val, - u32 mask) -{ - u32 tmp = vlv_cck_read(dev_priv, reg); - tmp &= ~mask; - tmp |= val; - vlv_cck_write(dev_priv, reg, tmp); -} - -static void band_gap_wa(struct drm_i915_private *dev_priv) +static void band_gap_reset(struct drm_i915_private *dev_priv) { mutex_lock(&dev_priv->dpio_lock); - /* Enable bandgap fix in GOP driver */ - vlv_cck_modify(dev_priv, 0x6D, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6E, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6F, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x00, 0x00008000, 0x00008000); - msleep(20); - vlv_cck_modify(dev_priv, 0x00, 0x00000000, 0x00008000); - msleep(20); - - /* Turn Display Trunk on */ - vlv_cck_modify(dev_priv, 0x6B, 0x00020000, 0x00030000); - msleep(20); - - vlv_cck_modify(dev_priv, 0x6C, 0x00020000, 0x00030000); - msleep(20); - - vlv_cck_modify(dev_priv, 0x6D, 0x00020000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6E, 0x00020000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6F, 0x00020000, 0x00030000); + vlv_flisdsi_write(dev_priv, 0x08, 0x0001); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0005); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0025); + udelay(150); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0000); + vlv_flisdsi_write(dev_priv, 0x08, 0x0000); mutex_unlock(&dev_priv->dpio_lock); - - /* Need huge delay, otherwise clock is not stable */ - msleep(100); } static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector) @@ -132,14 +101,47 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) vlv_enable_dsi_pll(encoder); } +static void intel_dsi_device_ready(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + int pipe = intel_crtc->pipe; + u32 val; + + DRM_DEBUG_KMS("\n"); + + val = I915_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + usleep_range(2000, 2500); +} static void intel_dsi_pre_enable(struct intel_encoder *encoder) { + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + DRM_DEBUG_KMS("\n"); + + if (intel_dsi->dev.dev_ops->panel_reset) + intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); + + /* put device in ready state */ + intel_dsi_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->send_otp_cmds) + intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); } static void intel_dsi_enable(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; @@ -147,41 +149,28 @@ static void intel_dsi_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - temp = I915_READ(MIPI_DEVICE_READY(pipe)); - if ((temp & DEVICE_READY) == 0) { - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp | DEVICE_READY); - } else if (temp & ULPS_STATE_MASK) { - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_EXIT); - /* - * We need to ensure that there is a minimum of 1 ms time - * available before clearing the UPLS exit state. - */ - msleep(2); - I915_WRITE(MIPI_DEVICE_READY(pipe), temp); - } - if (is_cmd_mode(intel_dsi)) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); - - if (is_vid_mode(intel_dsi)) { + else { msleep(20); /* XXX */ dpi_send_cmd(intel_dsi, TURN_ON); msleep(100); /* assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(pipe)); + temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK; + temp = temp | intel_dsi->port_bits; I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } - intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); + if (intel_dsi->dev.dev_ops->enable) + intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); } static void intel_dsi_disable(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; @@ -189,8 +178,6 @@ static void intel_dsi_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); - if (is_vid_mode(intel_dsi)) { dpi_send_cmd(intel_dsi, SHUTDOWN); msleep(10); @@ -203,20 +190,54 @@ static void intel_dsi_disable(struct intel_encoder *encoder) msleep(2); } - temp = I915_READ(MIPI_DEVICE_READY(pipe)); - if (temp & DEVICE_READY) { - temp &= ~DEVICE_READY; - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp); - } + /* if disable packets are sent before sending shutdown packet then in + * some next enable sequence send turn on packet error is observed */ + if (intel_dsi->dev.dev_ops->disable) + intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); } -static void intel_dsi_post_disable(struct intel_encoder *encoder) +static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + int pipe = intel_crtc->pipe; + u32 val; + DRM_DEBUG_KMS("\n"); + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + val = I915_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + + if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT) + == 0x00000), 30)) + DRM_ERROR("DSI LP not going Low\n"); + + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + usleep_range(2000, 2500); + vlv_disable_dsi_pll(encoder); } +static void intel_dsi_post_disable(struct intel_encoder *encoder) +{ + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + + DRM_DEBUG_KMS("\n"); + + intel_dsi_clear_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->disable_panel_power) + intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); +} static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) @@ -353,11 +374,8 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); - /* Update the DSI PLL */ - vlv_enable_dsi_pll(intel_encoder); - /* XXX: Location of the call */ - band_gap_wa(dev_priv); + band_gap_reset(dev_priv); /* escape clock divider, 20MHz, shared for A and C. device ready must be * off when doing this! txclkesc? */ @@ -374,11 +392,7 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff); I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff); - I915_WRITE(MIPI_DPHY_PARAM(pipe), - 0x3c << EXIT_ZERO_COUNT_SHIFT | - 0x1f << TRAIL_COUNT_SHIFT | - 0xc5 << CLK_ZERO_COUNT_SHIFT | - 0x1f << PREPARE_COUNT_SHIFT); + I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg); I915_WRITE(MIPI_DPI_RESOLUTION(pipe), adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | @@ -426,9 +440,9 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) adjusted_mode->htotal, bpp, intel_dsi->lane_count) + 1); } - I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), 8309); /* max */ - I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), 0x14); /* max */ - I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), 0xffff); /* max */ + I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout); + I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val); + I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val); /* dphy stuff */ @@ -443,29 +457,31 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) * * XXX: write MIPI_STOP_STATE_STALL? */ - I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), 0x46); + I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), + intel_dsi->hs_to_lp_count); /* XXX: low power clock equivalence in terms of byte clock. the number * of byte clocks occupied in one low power clock. based on txbyteclkhs * and txclkesc. txclkesc time / txbyteclk time * (105 + * MIPI_STOP_STATE_STALL) / 105.??? */ - I915_WRITE(MIPI_LP_BYTECLK(pipe), 4); + I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk); /* the bw essential for transmitting 16 long packets containing 252 * bytes meant for dcs write memory command is programmed in this * register in terms of byte clocks. based on dsi transfer rate and the * number of lanes configured the time taken to transmit 16 long packets * in a dsi stream varies. */ - I915_WRITE(MIPI_DBI_BW_CTRL(pipe), 0x820); + I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer); I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe), - 0xa << LP_HS_SSW_CNT_SHIFT | - 0x14 << HS_LP_PWR_SW_CNT_SHIFT); + intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | + intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); if (is_vid_mode(intel_dsi)) I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), - intel_dsi->video_mode_format); + intel_dsi->video_frmt_cfg_bits | + intel_dsi->video_mode_format); } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index c7765f3..b4a27ce 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -39,6 +39,13 @@ struct intel_dsi_device { struct intel_dsi_dev_ops { bool (*init)(struct intel_dsi_device *dsi); + void (*panel_reset)(struct intel_dsi_device *dsi); + + void (*disable_panel_power)(struct intel_dsi_device *dsi); + + /* one time programmable commands if needed */ + void (*send_otp_cmds)(struct intel_dsi_device *dsi); + /* This callback must be able to assume DSI commands can be sent */ void (*enable)(struct intel_dsi_device *dsi); @@ -89,6 +96,20 @@ struct intel_dsi { /* eot for MIPI_EOT_DISABLE register */ u32 eot_disable; + + u32 port_bits; + u32 bw_timer; + u32 dphy_reg; + u32 video_frmt_cfg_bits; + u16 lp_byte_clk; + + /* timeouts in byte clocks */ + u16 lp_rx_timeout; + u16 turn_arnd_val; + u16 rst_timer_val; + u16 hs_to_lp_count; + u16 clk_lp_to_hs_count; + u16 clk_hs_to_lp_count; }; static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 44279b2..ba79ec1 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -50,6 +50,8 @@ static const u32 lfsr_converts[] = { 71, 35 /* 91 - 92 */ }; +#ifdef DSI_CLK_FROM_RR + static u32 dsi_rr_formula(const struct drm_display_mode *mode, int pixel_format, int video_mode_format, int lane_count, bool eotp) @@ -121,7 +123,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, /* the dsi clock is divided by 2 in the hardware to get dsi ddr clock */ dsi_bit_clock_hz = bytes_per_x_frames_x_lanes * 8; - dsi_clk = dsi_bit_clock_hz / (1000 * 1000); + dsi_clk = dsi_bit_clock_hz / 1000; if (eotp && video_mode_format == VIDEO_MODE_BURST) dsi_clk *= 2; @@ -129,64 +131,37 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, return dsi_clk; } -#ifdef MNP_FROM_TABLE - -struct dsi_clock_table { - u32 freq; - u8 m; - u8 p; -}; - -static const struct dsi_clock_table dsi_clk_tbl[] = { - {300, 72, 6}, {313, 75, 6}, {323, 78, 6}, {333, 80, 6}, - {343, 82, 6}, {353, 85, 6}, {363, 87, 6}, {373, 90, 6}, - {383, 92, 6}, {390, 78, 5}, {393, 79, 5}, {400, 80, 5}, - {401, 80, 5}, {402, 80, 5}, {403, 81, 5}, {404, 81, 5}, - {405, 81, 5}, {406, 81, 5}, {407, 81, 5}, {408, 82, 5}, - {409, 82, 5}, {410, 82, 5}, {411, 82, 5}, {412, 82, 5}, - {413, 83, 5}, {414, 83, 5}, {415, 83, 5}, {416, 83, 5}, - {417, 83, 5}, {418, 84, 5}, {419, 84, 5}, {420, 84, 5}, - {430, 86, 5}, {440, 88, 5}, {450, 90, 5}, {460, 92, 5}, - {470, 75, 4}, {480, 77, 4}, {490, 78, 4}, {500, 80, 4}, - {510, 82, 4}, {520, 83, 4}, {530, 85, 4}, {540, 86, 4}, - {550, 88, 4}, {560, 90, 4}, {570, 91, 4}, {580, 70, 3}, - {590, 71, 3}, {600, 72, 3}, {610, 73, 3}, {620, 74, 3}, - {630, 76, 3}, {640, 77, 3}, {650, 78, 3}, {660, 79, 3}, - {670, 80, 3}, {680, 82, 3}, {690, 83, 3}, {700, 84, 3}, - {710, 85, 3}, {720, 86, 3}, {730, 88, 3}, {740, 89, 3}, - {750, 90, 3}, {760, 91, 3}, {770, 92, 3}, {780, 62, 2}, - {790, 63, 2}, {800, 64, 2}, {880, 70, 2}, {900, 72, 2}, - {1000, 80, 2}, /* dsi clock frequency in Mhz*/ -}; +#else -static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) +/* Get DSI clock from pixel clock */ +static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode, + int pixel_format, int lane_count) { - unsigned int i; - u8 m; - u8 n; - u8 p; - u32 m_seed; - - if (dsi_clk < 300 || dsi_clk > 1000) - return -ECHRNG; + u32 dsi_clk_khz; + u32 bpp; - for (i = 0; i <= ARRAY_SIZE(dsi_clk_tbl); i++) { - if (dsi_clk_tbl[i].freq > dsi_clk) - break; + switch (pixel_format) { + default: + case VID_MODE_FORMAT_RGB888: + case VID_MODE_FORMAT_RGB666_LOOSE: + bpp = 24; + break; + case VID_MODE_FORMAT_RGB666: + bpp = 18; + break; + case VID_MODE_FORMAT_RGB565: + bpp = 16; + break; } - m = dsi_clk_tbl[i].m; - p = dsi_clk_tbl[i].p; - m_seed = lfsr_converts[m - 62]; - n = 1; - dsi_mnp->dsi_pll_ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + p - 2); - dsi_mnp->dsi_pll_div = (n - 1) << DSI_PLL_N1_DIV_SHIFT | - m_seed << DSI_PLL_M1_DIV_SHIFT; + /* DSI data rate = pixel clock * bits per pixel / lane count + pixel clock is converted from KHz to Hz */ + dsi_clk_khz = DIV_ROUND_CLOSEST(mode->clock * bpp, lane_count); - return 0; + return dsi_clk_khz; } -#else +#endif static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) { @@ -194,36 +169,47 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) u32 ref_clk; u32 error; u32 tmp_error; - u32 target_dsi_clk; - u32 calc_dsi_clk; + int target_dsi_clk; + int calc_dsi_clk; u32 calc_m; u32 calc_p; u32 m_seed; - if (dsi_clk < 300 || dsi_clk > 1150) { + /* dsi_clk is expected in KHZ */ + if (dsi_clk < 300000 || dsi_clk > 1150000) { DRM_ERROR("DSI CLK Out of Range\n"); return -ECHRNG; } ref_clk = 25000; - target_dsi_clk = dsi_clk * 1000; + target_dsi_clk = dsi_clk; error = 0xFFFFFFFF; + tmp_error = 0xFFFFFFFF; calc_m = 0; calc_p = 0; for (m = 62; m <= 92; m++) { for (p = 2; p <= 6; p++) { - + /* Find the optimal m and p divisors + with minimal error +/- the required clock */ calc_dsi_clk = (m * ref_clk) / p; - if (calc_dsi_clk >= target_dsi_clk) { - tmp_error = calc_dsi_clk - target_dsi_clk; - if (tmp_error < error) { - error = tmp_error; - calc_m = m; - calc_p = p; - } + if (calc_dsi_clk == target_dsi_clk) { + calc_m = m; + calc_p = p; + error = 0; + break; + } else + tmp_error = abs(target_dsi_clk - calc_dsi_clk); + + if (tmp_error < error) { + error = tmp_error; + calc_m = m; + calc_p = p; } } + + if (error == 0) + break; } m_seed = lfsr_converts[calc_m - 62]; @@ -235,8 +221,6 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) return 0; } -#endif - /* * XXX: The muxing and gating is hard coded for now. Need to add support for * sharing PLLs with two DSI outputs. @@ -251,9 +235,8 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) struct dsi_mnp dsi_mnp; u32 dsi_clk; - dsi_clk = dsi_rr_formula(mode, intel_dsi->pixel_format, - intel_dsi->video_mode_format, - intel_dsi->lane_count, !intel_dsi->eot_disable); + dsi_clk = dsi_clk_from_pclk(mode, intel_dsi->pixel_format, + intel_dsi->lane_count); ret = dsi_calc_mnp(dsi_clk, &dsi_mnp); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6a6ad0c..6db0d9d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -130,9 +130,9 @@ static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, static void g4x_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val = I915_READ(VIDEO_DIP_CTL); @@ -167,9 +167,9 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, static void ibx_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -205,9 +205,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, static void cpt_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -246,9 +246,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, static void vlv_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -284,9 +284,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, static void hsw_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3deb58e..8bcb93a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -447,9 +447,19 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, 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); + /* + * Some old platform's BIOS love to wreak havoc while the lid is closed. + * We try to detect this here and undo any damage. The split for PCH + * platforms is rather conservative and a bit arbitrary expect that on + * those platforms VGA disabling requires actual legacy VGA I/O access, + * and as part of the cleanup in the hw state restore we also redisable + * the vga plane. + */ + if (!HAS_PCH_SPLIT(dev)) { + drm_modeset_lock_all(dev); + intel_modeset_setup_hw_state(dev, true); + drm_modeset_unlock_all(dev); + } dev_priv->modeset_restore = MODESET_DONE; @@ -745,57 +755,6 @@ static const struct dmi_system_id intel_no_lvds[] = { { } /* terminating entry */ }; -/** - * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID - * @dev: drm device - * @connector: LVDS connector - * - * Find the reduced downclock for LVDS in EDID. - */ -static void intel_find_lvds_downclock(struct drm_device *dev, - struct drm_display_mode *fixed_mode, - struct drm_connector *connector) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *scan; - int temp_downclock; - - temp_downclock = fixed_mode->clock; - list_for_each_entry(scan, &connector->probed_modes, head) { - /* - * If one mode has the same resolution with the fixed_panel - * mode while they have the different refresh rate, it means - * that the reduced downclock is found for the LVDS. In such - * case we can set the different FPx0/1 to dynamically select - * between low and high frequency. - */ - if (scan->hdisplay == fixed_mode->hdisplay && - scan->hsync_start == fixed_mode->hsync_start && - scan->hsync_end == fixed_mode->hsync_end && - scan->htotal == fixed_mode->htotal && - scan->vdisplay == fixed_mode->vdisplay && - scan->vsync_start == fixed_mode->vsync_start && - scan->vsync_end == fixed_mode->vsync_end && - scan->vtotal == fixed_mode->vtotal) { - if (scan->clock < temp_downclock) { - /* - * The downclock is already found. But we - * expect to find the lower downclock. - */ - temp_downclock = scan->clock; - } - } - } - if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) { - /* We found the downclock for LVDS. */ - dev_priv->lvds_downclock_avail = 1; - dev_priv->lvds_downclock = temp_downclock; - DRM_DEBUG_KMS("LVDS downclock is found in EDID. " - "Normal clock %dKhz, downclock %dKhz\n", - fixed_mode->clock, temp_downclock); - } -} - /* * Enumerate the child dev array parsed from VBT to check whether * the LVDS is present. @@ -1073,8 +1032,22 @@ void intel_lvds_init(struct drm_device *dev) fixed_mode = drm_mode_duplicate(dev, scan); if (fixed_mode) { - intel_find_lvds_downclock(dev, fixed_mode, - connector); + intel_connector->panel.downclock_mode = + intel_find_panel_downclock(dev, + fixed_mode, connector); + if (intel_connector->panel.downclock_mode != + NULL && i915_lvds_downclock) { + /* We found the downclock for LVDS. */ + dev_priv->lvds_downclock_avail = true; + dev_priv->lvds_downclock = + intel_connector->panel. + downclock_mode->clock; + DRM_DEBUG_KMS("LVDS downclock is found" + " in EDID. Normal clock %dKhz, " + "downclock %dKhz\n", + fixed_mode->clock, + dev_priv->lvds_downclock); + } goto out; } } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index a8febbd3..3da259e 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -64,7 +64,7 @@ struct opregion_header { u8 driver_ver[16]; u32 mboxes; u8 reserved[164]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #1: public ACPI methods */ struct opregion_acpi { @@ -86,7 +86,7 @@ struct opregion_acpi { u32 cnot; /* current OS notification */ u32 nrdy; /* driver status */ u8 rsvd2[60]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #2: SWSCI */ struct opregion_swsci { @@ -94,7 +94,7 @@ struct opregion_swsci { u32 parm; /* command parameters */ u32 dslp; /* driver sleep time-out */ u8 rsvd[244]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #3: ASLE */ struct opregion_asle { @@ -115,7 +115,7 @@ struct opregion_asle { u32 srot; /* supported rotation angles */ u32 iuer; /* IUER events */ u8 rsvd[86]; -} __attribute__((packed)); +} __packed; /* Driver readiness indicator */ #define ASLE_ARDY_READY (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e480cf4..20ebc3e 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -845,11 +845,14 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; + intel_runtime_pm_get(dev_priv); mutex_lock(&dev->mode_config.mutex); ret = intel_panel_get_backlight(connector); mutex_unlock(&dev->mode_config.mutex); + intel_runtime_pm_put(dev_priv); return ret; } @@ -1104,6 +1107,59 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) intel_backlight_device_unregister(intel_connector); } +/** + * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID + * @dev: drm device + * @fixed_mode : panel native mode + * @connector: LVDS/eDP connector + * + * Return downclock_avail + * Find the reduced downclock for LVDS/eDP in EDID. + */ +struct drm_display_mode * +intel_find_panel_downclock(struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector) +{ + struct drm_display_mode *scan, *tmp_mode; + int temp_downclock; + + temp_downclock = fixed_mode->clock; + tmp_mode = NULL; + + list_for_each_entry(scan, &connector->probed_modes, head) { + /* + * If one mode has the same resolution with the fixed_panel + * mode while they have the different refresh rate, it means + * that the reduced downclock is found. In such + * case we can set the different FPx0/1 to dynamically select + * between low and high frequency. + */ + if (scan->hdisplay == fixed_mode->hdisplay && + scan->hsync_start == fixed_mode->hsync_start && + scan->hsync_end == fixed_mode->hsync_end && + scan->htotal == fixed_mode->htotal && + scan->vdisplay == fixed_mode->vdisplay && + scan->vsync_start == fixed_mode->vsync_start && + scan->vsync_end == fixed_mode->vsync_end && + scan->vtotal == fixed_mode->vtotal) { + if (scan->clock < temp_downclock) { + /* + * The downclock is already found. But we + * expect to find the lower downclock. + */ + temp_downclock = scan->clock; + tmp_mode = scan; + } + } + } + + if (temp_downclock < fixed_mode->clock) + return drm_mode_duplicate(dev, tmp_mode); + else + return NULL; +} + /* Set up chip specific backlight functions */ void intel_panel_init_backlight_funcs(struct drm_device *dev) { @@ -1157,4 +1213,8 @@ void intel_panel_fini(struct intel_panel *panel) if (panel->fixed_mode) drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); + + if (panel->downclock_mode) + drm_mode_destroy(intel_connector->base.dev, + panel->downclock_mode); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e6d98fe..04b28f9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -30,7 +30,9 @@ #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" #include <linux/module.h> +#include <linux/vgaarb.h> #include <drm/i915_powerwell.h> +#include <linux/pm_runtime.h> /** * RC6 is a special power stage which allows the GPU to enter an very @@ -86,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; @@ -96,32 +98,40 @@ 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) 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 */ 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; + 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); @@ -136,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; @@ -145,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... */ @@ -210,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; @@ -219,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); @@ -232,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... */ @@ -272,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; @@ -329,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; @@ -367,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; @@ -381,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; @@ -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; } @@ -602,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; @@ -5257,19 +5257,33 @@ 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) | 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)); + + /* 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) @@ -5681,14 +5695,71 @@ 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; + + /* + * 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), + 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); + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED; enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST; @@ -5705,42 +5776,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); } } } @@ -5748,17 +5791,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, @@ -5951,31 +6003,86 @@ 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) { 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; + + /* This value was pulled out of someone's hat */ + I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - /* 855GM needs testing */ } /* For cxsr */ diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2abeab0..95bdfb3 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -952,7 +952,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, unsigned if_index, uint8_t tx_rate, - uint8_t *data, unsigned length) + const uint8_t *data, unsigned length) { uint8_t set_buf_index[2] = { if_index, 0 }; uint8_t hbuf_size, tmp[8]; diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 770bdd6..2e2d4eb 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -59,7 +59,7 @@ struct intel_sdvo_caps { unsigned int stall_support:1; unsigned int pad:1; u16 output_flags; -} __attribute__((packed)); +} __packed; /* Note: SDVO detailed timing flags match EDID misc flags. */ #define DTD_FLAG_HSYNC_POSITIVE (1 << 1) @@ -94,12 +94,12 @@ struct intel_sdvo_dtd { u8 v_sync_off_high; u8 reserved; } part2; -} __attribute__((packed)); +} __packed; struct intel_sdvo_pixel_clock_range { u16 min; /**< pixel clock, in 10kHz units */ u16 max; /**< pixel clock, in 10kHz units */ -} __attribute__((packed)); +} __packed; struct intel_sdvo_preferred_input_timing_args { u16 clock; @@ -108,7 +108,7 @@ struct intel_sdvo_preferred_input_timing_args { u8 interlace:1; u8 scaled:1; u8 pad:6; -} __attribute__((packed)); +} __packed; /* I2C registers for SDVO */ #define SDVO_I2C_ARG_0 0x07 @@ -162,7 +162,7 @@ struct intel_sdvo_get_trained_inputs_response { unsigned int input0_trained:1; unsigned int input1_trained:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; /** Returns a struct intel_sdvo_output_flags of active outputs. */ #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 @@ -219,7 +219,7 @@ struct intel_sdvo_get_interrupt_event_source_response { unsigned int ambient_light_interrupt:1; unsigned int hdmi_audio_encrypt_change:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; /** * Selects which input is affected by future input commands. @@ -232,7 +232,7 @@ struct intel_sdvo_get_interrupt_event_source_response { struct intel_sdvo_set_target_input_args { unsigned int target_1:1; unsigned int pad:7; -} __attribute__((packed)); +} __packed; /** * Takes a struct intel_sdvo_output_flags of which outputs are targeted by @@ -370,7 +370,7 @@ struct intel_sdvo_tv_format { unsigned int hdtv_std_eia_7702a_480i_60:1; unsigned int hdtv_std_eia_7702a_480p_60:1; unsigned int pad:3; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_TV_FORMAT 0x28 @@ -401,7 +401,7 @@ struct intel_sdvo_sdtv_resolution_request { unsigned int secam_l:1; unsigned int secam_60:1; unsigned int pad:5; -} __attribute__((packed)); +} __packed; struct intel_sdvo_sdtv_resolution_reply { unsigned int res_320x200:1; @@ -426,7 +426,7 @@ struct intel_sdvo_sdtv_resolution_reply { unsigned int res_1024x768:1; unsigned int res_1280x1024:1; unsigned int pad:5; -} __attribute__((packed)); +} __packed; /* Get supported resolution with squire pixel aspect ratio that can be scaled for the requested HDTV format */ @@ -463,7 +463,7 @@ struct intel_sdvo_hdtv_resolution_request { unsigned int hdtv_std_eia_7702a_480i_60:1; unsigned int hdtv_std_eia_7702a_480p_60:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; struct intel_sdvo_hdtv_resolution_reply { unsigned int res_640x480:1; @@ -517,7 +517,7 @@ struct intel_sdvo_hdtv_resolution_reply { unsigned int res_1280x768:1; unsigned int pad5:7; -} __attribute__((packed)); +} __packed; /* Get supported power state returns info for encoder and monitor, rely on last SetTargetInput and SetTargetOutput calls */ @@ -557,13 +557,13 @@ struct sdvo_panel_power_sequencing { unsigned int t4_high:2; unsigned int pad:6; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL 0x30 struct sdvo_max_backlight_reply { u8 max_value; u8 default_value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_BACKLIGHT_LEVEL 0x31 #define SDVO_CMD_SET_BACKLIGHT_LEVEL 0x32 @@ -573,14 +573,14 @@ struct sdvo_get_ambient_light_reply { u16 trip_low; u16 trip_high; u16 value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_SET_AMBIENT_LIGHT 0x34 struct sdvo_set_ambient_light_reply { u16 trip_low; u16 trip_high; unsigned int enable:1; unsigned int pad:7; -} __attribute__((packed)); +} __packed; /* Set display power state */ #define SDVO_CMD_SET_DISPLAY_POWER_STATE 0x7d @@ -608,7 +608,7 @@ struct intel_sdvo_enhancements_reply { unsigned int dither:1; unsigned int tv_chroma_filter:1; unsigned int tv_luma_filter:1; -} __attribute__((packed)); +} __packed; /* Picture enhancement limits below are dependent on the current TV format, * and thus need to be queried and set after it. @@ -630,7 +630,7 @@ struct intel_sdvo_enhancements_reply { struct intel_sdvo_enhancement_limits_reply { u16 max_value; u16 default_value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_LVDS_PANEL_INFORMATION 0x7f #define SDVO_CMD_SET_LVDS_PANEL_INFORMATION 0x80 @@ -671,7 +671,7 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_SET_TV_LUMA_FILTER 0x79 struct intel_sdvo_enhancements_arg { u16 value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_DOT_CRAWL 0x70 #define SDVO_CMD_SET_DOT_CRAWL 0x71 @@ -727,4 +727,4 @@ struct intel_sdvo_enhancements_arg { struct intel_sdvo_encode { u8 dvi_rev; u8 hdmi_rev; -} __attribute__ ((packed)); +} __packed; diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index cc6fbcd..0954f13 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -249,3 +249,17 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, return; } } + +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_WRITE, reg, &val); +} diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 0db5472..2c8143c 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -150,6 +150,13 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) { int ret = 0; + /* On VLV, FIFO will be shared by both SW and HW. + * So, we need to read the FREE_ENTRIES everytime */ + if (IS_VALLEYVIEW(dev_priv->dev)) + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) & + GT_FIFO_FREE_ENTRIES_MASK; + if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) { int loop = 500; u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; @@ -325,6 +332,11 @@ void intel_uncore_early_sanitize(struct drm_device *dev) DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size); } + /* clear out old GT FIFO errors */ + if (IS_GEN6(dev) || IS_GEN7(dev)) + __raw_i915_write32(dev_priv, GTFIFODBG, + __raw_i915_read32(dev_priv, GTFIFODBG)); + intel_uncore_forcewake_reset(dev); } @@ -333,8 +345,6 @@ void intel_uncore_sanitize(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 reg_val; - intel_uncore_forcewake_reset(dev); - /* BIOS often leaves RC6 enabled, but disable it for hw init */ intel_disable_gt_powersave(dev); @@ -365,6 +375,8 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) if (!dev_priv->uncore.funcs.force_wake_get) return; + intel_runtime_pm_get(dev_priv); + /* Redirect to VLV specific routine */ if (IS_VALLEYVIEW(dev_priv->dev)) return vlv_force_wake_get(dev_priv, fw_engine); @@ -398,6 +410,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) 1); } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_runtime_pm_put(dev_priv); } /* We give fast paths for the really cool registers */ @@ -432,6 +446,13 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) } } +static void +assert_device_not_suspended(struct drm_i915_private *dev_priv) +{ + WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended, + "Device suspended\n"); +} + #define REG_READ_HEADER(x) \ unsigned long irqflags; \ u##x val = 0; \ @@ -535,12 +556,15 @@ __gen4_read(64) trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) +#define REG_WRITE_FOOTER \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags) + #define __gen4_write(x) \ static void \ gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ REG_WRITE_HEADER; \ __raw_i915_write##x(dev_priv, reg, val); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __gen5_write(x) \ @@ -549,7 +573,7 @@ gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace REG_WRITE_HEADER; \ ilk_dummy_write(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __gen6_write(x) \ @@ -560,11 +584,12 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + assert_device_not_suspended(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __hsw_write(x) \ @@ -575,13 +600,14 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + assert_device_not_suspended(dev_priv); \ hsw_unclaimed_reg_clear(dev_priv, reg); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ hsw_unclaimed_reg_check(dev_priv, reg); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } static const u32 gen8_shadowed_regs[] = { @@ -608,7 +634,7 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg) #define __gen8_write(x) \ static void \ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ - bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \ + bool __needs_put = reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg); \ REG_WRITE_HEADER; \ if (__needs_put) { \ dev_priv->uncore.funcs.force_wake_get(dev_priv, \ @@ -619,7 +645,7 @@ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace dev_priv->uncore.funcs.force_wake_put(dev_priv, \ FORCEWAKE_ALL); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } __gen8_write(8) @@ -648,6 +674,7 @@ __gen4_write(64) #undef __gen6_write #undef __gen5_write #undef __gen4_write +#undef REG_WRITE_FOOTER #undef REG_WRITE_HEADER void intel_uncore_init(struct drm_device *dev) |