diff options
49 files changed, 3559 insertions, 2677 deletions
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 7ff1d0d208a7..2d68054f9795 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ -obj-$(CONFIG_AGP) += agp/ +obj-y += agp/ obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index d8b1b576556c..c528f96ee204 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -68,6 +68,7 @@ config AGP_AMD64 config AGP_INTEL tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support" depends on AGP && X86 + select INTEL_GTT help This option gives you AGP support for the GLX component of X on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875, @@ -155,3 +156,7 @@ config AGP_SGI_TIOCA This option gives you AGP GART support for the SGI TIO chipset for IA64 processors. +config INTEL_GTT + tristate + depends on X86 && PCI + diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 8eb56e273e75..604489bcdbf9 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o obj-$(CONFIG_AGP_PARISC) += parisc-agp.o obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o -obj-$(CONFIG_AGP_INTEL) += intel-gtt.o +obj-$(CONFIG_INTEL_GTT) += intel-gtt.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o obj-$(CONFIG_AGP_SIS) += sis-agp.o diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a426ee1f57a6..9ef0a48a5b28 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -14,9 +14,6 @@ #include "intel-agp.h" #include <drm/intel-gtt.h> -int intel_agp_enabled; -EXPORT_SYMBOL(intel_agp_enabled); - static int intel_fetch_size(void) { int i; @@ -814,8 +811,6 @@ static int agp_intel_probe(struct pci_dev *pdev, found_gmch: pci_set_drvdata(pdev, bridge); err = agp_add_bridge(bridge); - if (!err) - intel_agp_enabled = 1; return err; } diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index b8e2014cb9cb..078968d8d07d 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -94,6 +94,7 @@ static struct _intel_private { #define IS_IRONLAKE intel_private.driver->is_ironlake #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, struct sg_table *st) @@ -168,6 +169,7 @@ static void i8xx_destroy_pages(struct page *page) __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); } +#endif #define I810_GTT_ORDER 4 static int i810_setup(void) @@ -209,6 +211,7 @@ static void i810_cleanup(void) free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -289,6 +292,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr) } kfree(curr); } +#endif static int intel_gtt_setup_scratch_page(void) { @@ -647,7 +651,9 @@ static int intel_gtt_init(void) return -ENOMEM; } +#if IS_ENABLED(CONFIG_AGP_INTEL) global_cache_flush(); /* FIXME: ? */ +#endif intel_private.stolen_size = intel_gtt_stolen_size(); @@ -671,6 +677,7 @@ static int intel_gtt_init(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_fetch_size(void) { int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); @@ -689,6 +696,7 @@ static int intel_fake_agp_fetch_size(void) return 0; } +#endif static void i830_cleanup(void) { @@ -801,6 +809,7 @@ static int i830_setup(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) { agp_bridge->gatt_table_real = NULL; @@ -825,6 +834,7 @@ static int intel_fake_agp_configure(void) return 0; } +#endif static bool i830_check_flags(unsigned int flags) { @@ -863,6 +873,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, } EXPORT_SYMBOL(intel_gtt_insert_sg_entries); +#if IS_ENABLED(CONFIG_AGP_INTEL) static void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, struct page **pages, @@ -928,6 +939,7 @@ out_err: mem->is_flushed = true; return ret; } +#endif void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) { @@ -941,6 +953,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) } EXPORT_SYMBOL(intel_gtt_clear_range); +#if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_remove_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -982,6 +995,7 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, /* always return NULL for other allocation types for now */ return NULL; } +#endif static int intel_alloc_chipset_flush_resource(void) { @@ -1138,6 +1152,7 @@ static int i9xx_setup(void) return 0; } +#if IS_ENABLED(CONFIG_AGP_INTEL) static const struct agp_bridge_driver intel_fake_agp_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, @@ -1159,6 +1174,7 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, }; +#endif static const struct intel_gtt_driver i81x_gtt_driver = { .gen = 1, @@ -1376,11 +1392,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, intel_private.refcount++; +#if IS_ENABLED(CONFIG_AGP_INTEL) if (bridge) { bridge->driver = &intel_fake_agp_driver; bridge->dev_private_data = &intel_private; bridge->dev = bridge_pdev; } +#endif intel_private.bridge_dev = pci_dev_get(bridge_pdev); diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 6199d0b5b958..73ed59eff139 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -1,8 +1,10 @@ config DRM_I915 tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" depends on DRM - depends on AGP - depends on AGP_INTEL + depends on X86 && PCI + depends on (AGP || AGP=n) + select INTEL_GTT + select AGP_INTEL if AGP # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs select SHMEM @@ -35,15 +37,14 @@ config DRM_I915 config DRM_I915_KMS bool "Enable modesetting on intel by default" depends on DRM_I915 + default y help - Choose this option if you want kernel modesetting enabled by default, - and you have a new enough userspace to support this. Running old - userspaces with this enabled will cause pain. Note that this causes - the driver to bind to PCI devices, which precludes loading things - like intelfb. + Choose this option if you want kernel modesetting enabled by default. + + If in doubt, say "Y". config DRM_I915_FBDEV - bool "Enable legacy fbdev support for the modesettting intel driver" + bool "Enable legacy fbdev support for the modesetting intel driver" depends on DRM_I915 select DRM_KMS_FB_HELPER select FB_CFB_FILLRECT @@ -55,9 +56,12 @@ config DRM_I915_FBDEV support. Note that this support also provide the linux console support on top of the intel modesetting driver. + If in doubt, say "Y". + config DRM_I915_PRELIMINARY_HW_SUPPORT bool "Enable preliminary support for prerelease Intel hardware by default" depends on DRM_I915 + default n help Choose this option if you have prerelease Intel hardware and want the i915 driver to support it by default. You can enable such support at @@ -65,3 +69,15 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT option changes the default for that module option. If in doubt, say "N". + +config DRM_I915_UMS + bool "Enable userspace modesetting on Intel hardware (DEPRECATED)" + depends on DRM_I915 + default n + help + Choose this option if you still need userspace modesetting. + + Userspace modesetting is deprecated for quite some time now, so + enable this only if you have ancient versions of the DDX drivers. + + If in doubt, say "N". diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 41838eaa799c..da682cbcb806 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -4,7 +4,6 @@ ccflags-y := -Iinclude/drm i915-y := i915_drv.o i915_dma.o i915_irq.o \ - i915_debugfs.o \ i915_gpu_error.o \ i915_suspend.o \ i915_gem.o \ @@ -55,6 +54,8 @@ i915-$(CONFIG_ACPI) += intel_acpi.o i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o +i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o + obj-$(CONFIG_DRM_I915) += i915.o CFLAGS_i915_trace_points.o := -I$(src) diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index c4a255be6979..954acb2c7021 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -87,49 +87,6 @@ struct ns2501_priv { * when switching the resolution. */ -static void enable_dvo(struct intel_dvo_device *dvo) -{ - struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); - struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); - struct drm_i915_private *dev_priv = bus->dev_priv; - - DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__); - - ns->dvoc = I915_READ(DVO_C); - ns->pll_a = I915_READ(_DPLL_A); - ns->srcdim = I915_READ(DVOC_SRCDIM); - ns->fw_blc = I915_READ(FW_BLC); - - I915_WRITE(DVOC, 0x10004084); - I915_WRITE(_DPLL_A, 0xd0820000); - I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768 - I915_WRITE(FW_BLC, 0x1080304); - - I915_WRITE(DVOC, 0x90004084); -} - -/* - * Restore the I915 registers modified by the above - * trigger function. - */ -static void restore_dvo(struct intel_dvo_device *dvo) -{ - struct i2c_adapter *adapter = dvo->i2c_bus; - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); - struct drm_i915_private *dev_priv = bus->dev_priv; - struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); - - I915_WRITE(DVOC, ns->dvoc); - I915_WRITE(_DPLL_A, ns->pll_a); - I915_WRITE(DVOC_SRCDIM, ns->srcdim); - I915_WRITE(FW_BLC, ns->fw_blc); -} - /* ** Read a register from the ns2501. ** Returns true if successful, false otherwise. @@ -300,7 +257,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, struct drm_display_mode *adjusted_mode) { bool ok; - bool restore = false; + int retries = 10; struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); DRM_DEBUG_KMS @@ -476,20 +433,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo, ns->reg_8_shadow |= NS2501_8_BPAS; } ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow); - - if (!ok) { - if (restore) - restore_dvo(dvo); - enable_dvo(dvo); - restore = true; - } - } while (!ok); - /* - * Restore the old i915 registers before - * forcing the ns2501 on. - */ - if (restore) - restore_dvo(dvo); + } while (!ok && retries--); } /* set the NS2501 power state */ @@ -510,7 +454,7 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo) static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) { bool ok; - bool restore = false; + int retries = 10; struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); unsigned char ch; @@ -537,16 +481,7 @@ static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) ok &= ns2501_writeb(dvo, 0x35, enable ? 0xff : 0x00); - if (!ok) { - if (restore) - restore_dvo(dvo); - enable_dvo(dvo); - restore = true; - } - } while (!ok); - - if (restore) - restore_dvo(dvo); + } while (!ok && retries--); } } diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6ed45a984230..b2b46c52294c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -40,8 +40,6 @@ #include <drm/i915_drm.h> #include "i915_drv.h" -#if defined(CONFIG_DEBUG_FS) - enum { ACTIVE_LIST, INACTIVE_LIST, @@ -406,16 +404,26 @@ static int i915_gem_object_info(struct seq_file *m, void* data) seq_putc(m, '\n'); list_for_each_entry_reverse(file, &dev->filelist, lhead) { struct file_stats stats; + struct task_struct *task; memset(&stats, 0, sizeof(stats)); idr_for_each(&file->object_idr, per_file_stats, &stats); + /* + * Although we have a valid reference on file->pid, that does + * not guarantee that the task_struct who called get_pid() is + * still alive (e.g. get_pid(current) => fork() => exit()). + * Therefore, we need to protect this ->comm access using RCU. + */ + rcu_read_lock(); + task = pid_task(file->pid, PIDTYPE_PID); seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n", - get_pid_task(file->pid, PIDTYPE_PID)->comm, + task ? task->comm : "<unknown>", stats.count, stats.total, stats.active, stats.inactive, stats.unbound); + rcu_read_unlock(); } mutex_unlock(&dev->struct_mutex); @@ -564,10 +572,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 +595,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 +722,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 +916,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 +933,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,9 +961,9 @@ 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); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); reqf = I915_READ(GEN6_RPNSWREQ); reqf &= ~GEN6_TURBO_DISABLE; @@ -970,7 +986,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT; cagf *= GT_FREQUENCY_MULTIPLIER; - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); @@ -1018,23 +1034,24 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); - val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1); + val = valleyview_rps_max_freq(dev_priv); seq_printf(m, "max GPU freq: %d MHz\n", - vlv_gpu_freq(dev_priv->mem_freq, val)); + vlv_gpu_freq(dev_priv, val)); - val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM); + val = valleyview_rps_min_freq(dev_priv); seq_printf(m, "min GPU freq: %d MHz\n", - vlv_gpu_freq(dev_priv->mem_freq, val)); + vlv_gpu_freq(dev_priv, val)); seq_printf(m, "current GPU freq: %d MHz\n", - vlv_gpu_freq(dev_priv->mem_freq, - (freq_sts >> 8) & 0xff)); + vlv_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff)); mutex_unlock(&dev_priv->rps.hw_lock); } else { 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) @@ -1048,6 +1065,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); @@ -1055,6 +1073,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; @@ -1076,12 +1096,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; @@ -1099,11 +1121,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) ? @@ -1154,6 +1178,50 @@ static int ironlake_drpc_info(struct seq_file *m) return 0; } +static int vlv_drpc_info(struct seq_file *m) +{ + + 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; + u32 rpmodectl1, rcctl1; + unsigned fw_rendercount = 0, fw_mediacount = 0; + + rpmodectl1 = I915_READ(GEN6_RP_CONTROL); + rcctl1 = I915_READ(GEN6_RC_CONTROL); + + seq_printf(m, "Video Turbo Mode: %s\n", + yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); + seq_printf(m, "Turbo enabled: %s\n", + yesno(rpmodectl1 & GEN6_RP_ENABLE)); + seq_printf(m, "HW control enabled: %s\n", + yesno(rpmodectl1 & GEN6_RP_ENABLE)); + seq_printf(m, "SW control enabled: %s\n", + yesno((rpmodectl1 & GEN6_RP_MEDIA_MODE_MASK) == + GEN6_RP_MEDIA_SW_MODE)); + seq_printf(m, "RC6 Enabled: %s\n", + yesno(rcctl1 & (GEN7_RC_CTL_TO_MODE | + GEN6_RC_CTL_EI_MODE(1)))); + seq_printf(m, "Render Power Well: %s\n", + (I915_READ(VLV_GTLC_PW_STATUS) & + VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up" : "Down"); + seq_printf(m, "Media Power Well: %s\n", + (I915_READ(VLV_GTLC_PW_STATUS) & + VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down"); + + spin_lock_irq(&dev_priv->uncore.lock); + fw_rendercount = dev_priv->uncore.fw_rendercount; + fw_mediacount = dev_priv->uncore.fw_mediacount; + spin_unlock_irq(&dev_priv->uncore.lock); + + seq_printf(m, "Forcewake Render Count = %u\n", fw_rendercount); + seq_printf(m, "Forcewake Media Count = %u\n", fw_mediacount); + + + return 0; +} + + static int gen6_drpc_info(struct seq_file *m) { @@ -1167,6 +1235,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; @@ -1192,6 +1261,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", @@ -1256,7 +1327,9 @@ static int i915_drpc_info(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; - if (IS_GEN6(dev) || IS_GEN7(dev)) + if (IS_VALLEYVIEW(dev)) + return vlv_drpc_info(m); + else if (IS_GEN6(dev) || IS_GEN7(dev)) return gen6_drpc_info(m); else return ironlake_drpc_info(m); @@ -1268,7 +1341,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - if (!I915_HAS_FBC(dev)) { + if (!HAS_FBC(dev)) { seq_puts(m, "FBC unsupported on this chipset\n"); return 0; } @@ -1330,7 +1403,7 @@ static int i915_ips_status(struct seq_file *m, void *unused) return 0; } - if (I915_READ(IPS_CTL) & IPS_ENABLE) + if (IS_BROADWELL(dev) || I915_READ(IPS_CTL) & IPS_ENABLE) seq_puts(m, "enabled\n"); else seq_puts(m, "disabled\n"); @@ -1406,6 +1479,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"); @@ -1422,6 +1496,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; @@ -1437,8 +1512,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); @@ -1565,13 +1642,21 @@ static int i915_gen6_forcewake_count_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; - unsigned forcewake_count; + unsigned forcewake_count = 0, fw_rendercount = 0, fw_mediacount = 0; spin_lock_irq(&dev_priv->uncore.lock); - forcewake_count = dev_priv->uncore.forcewake_count; + if (IS_VALLEYVIEW(dev)) { + fw_rendercount = dev_priv->uncore.fw_rendercount; + fw_mediacount = dev_priv->uncore.fw_mediacount; + } else + forcewake_count = dev_priv->uncore.forcewake_count; spin_unlock_irq(&dev_priv->uncore.lock); - seq_printf(m, "forcewake count = %u\n", forcewake_count); + if (IS_VALLEYVIEW(dev)) { + seq_printf(m, "fw_rendercount = %u\n", fw_rendercount); + seq_printf(m, "fw_mediacount = %u\n", fw_mediacount); + } else + seq_printf(m, "forcewake count = %u\n", forcewake_count); return 0; } @@ -1610,6 +1695,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)); @@ -1641,6 +1727,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; @@ -1701,16 +1788,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; @@ -1735,28 +1825,28 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL)); - seq_printf(m, "DPIO_DIV_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_DIV_A)); - seq_printf(m, "DPIO_DIV_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_DIV_B)); + seq_printf(m, "DPIO PLL DW3 CH0 : 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(0))); + seq_printf(m, "DPIO PLL DW3 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(1))); - seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_REFSFR_A)); - seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_REFSFR_B)); + seq_printf(m, "DPIO PLL DW5 CH0: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(0))); + seq_printf(m, "DPIO PLL DW5 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(1))); - seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_CORE_CLK_A)); - seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_CORE_CLK_B)); + seq_printf(m, "DPIO PLL DW7 CH0: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(0))); + seq_printf(m, "DPIO PLL DW7 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(1))); - seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_LPF_COEFF_A)); - seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, _DPIO_LPF_COEFF_B)); + seq_printf(m, "DPIO PLL DW10 CH0: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(0))); + seq_printf(m, "DPIO PLL DW10 CH1: 0x%08x\n", + vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(1))); seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", - vlv_dpio_read(dev_priv, PIPE_A, DPIO_FASTCLK_DISABLE)); + vlv_dpio_read(dev_priv, PIPE_A, VLV_CMN_DW0)); mutex_unlock(&dev_priv->dpio_lock); @@ -1784,6 +1874,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)); @@ -1796,6 +1888,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; } @@ -1845,6 +1938,76 @@ static int i915_pc8_status(struct seq_file *m, void *unused) return 0; } +static const char *power_domain_str(enum intel_display_power_domain domain) +{ + switch (domain) { + case POWER_DOMAIN_PIPE_A: + return "PIPE_A"; + case POWER_DOMAIN_PIPE_B: + return "PIPE_B"; + case POWER_DOMAIN_PIPE_C: + return "PIPE_C"; + case POWER_DOMAIN_PIPE_A_PANEL_FITTER: + return "PIPE_A_PANEL_FITTER"; + case POWER_DOMAIN_PIPE_B_PANEL_FITTER: + return "PIPE_B_PANEL_FITTER"; + case POWER_DOMAIN_PIPE_C_PANEL_FITTER: + return "PIPE_C_PANEL_FITTER"; + case POWER_DOMAIN_TRANSCODER_A: + return "TRANSCODER_A"; + case POWER_DOMAIN_TRANSCODER_B: + return "TRANSCODER_B"; + case POWER_DOMAIN_TRANSCODER_C: + return "TRANSCODER_C"; + case POWER_DOMAIN_TRANSCODER_EDP: + return "TRANSCODER_EDP"; + case POWER_DOMAIN_VGA: + return "VGA"; + case POWER_DOMAIN_AUDIO: + return "AUDIO"; + case POWER_DOMAIN_INIT: + return "INIT"; + default: + WARN_ON(1); + return "?"; + } +} + +static int i915_power_domain_info(struct seq_file *m, void *unused) +{ + 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; + struct i915_power_domains *power_domains = &dev_priv->power_domains; + int i; + + mutex_lock(&power_domains->lock); + + seq_printf(m, "%-25s %s\n", "Power well/domain", "Use count"); + for (i = 0; i < power_domains->power_well_count; i++) { + struct i915_power_well *power_well; + enum intel_display_power_domain power_domain; + + power_well = &power_domains->power_wells[i]; + seq_printf(m, "%-25s %d\n", power_well->name, + power_well->count); + + for (power_domain = 0; power_domain < POWER_DOMAIN_NUM; + power_domain++) { + if (!(BIT(power_domain) & power_well->domains)) + continue; + + seq_printf(m, " %-23s %d\n", + power_domain_str(power_domain), + power_domains->domain_use_count[power_domain]); + } + } + + mutex_unlock(&power_domains->lock); + + return 0; +} + struct pipe_crc_info { const char *name; struct drm_device *dev; @@ -1857,6 +2020,9 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep) struct drm_i915_private *dev_priv = info->dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; + if (info->pipe >= INTEL_INFO(info->dev)->num_pipes) + return -ENODEV; + spin_lock_irq(&pipe_crc->lock); if (pipe_crc->opened) { @@ -2005,8 +2171,8 @@ static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor, info->dev = dev; ent = debugfs_create_file(info->name, S_IRUGO, root, info, &i915_pipe_crc_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; return drm_add_fake_info_node(minor, ent, info); } @@ -2347,7 +2513,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - u32 val; + u32 val = 0; /* shut up gcc */ int ret; if (pipe_crc->source == source) @@ -2742,7 +2908,7 @@ i915_drop_caches_set(void *data, u64 val) struct i915_vma *vma, *x; int ret; - DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val); + DRM_DEBUG("Dropping caches: 0x%08llx\n", val); /* No need to check and wait for gpu resets, only libdrm auto-restarts * on ioctls on -EAGAIN. */ @@ -2810,8 +2976,7 @@ i915_max_freq_get(void *data, u64 *val) return ret; if (IS_VALLEYVIEW(dev)) - *val = vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.max_delay); + *val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay); else *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -2841,9 +3006,9 @@ i915_max_freq_set(void *data, u64 val) * Turbo will still be enabled, but won't go above the set value. */ if (IS_VALLEYVIEW(dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); dev_priv->rps.max_delay = val; - gen6_set_rps(dev, val); + valleyview_set_rps(dev, val); } else { do_div(val, GT_FREQUENCY_MULTIPLIER); dev_priv->rps.max_delay = val; @@ -2876,8 +3041,7 @@ i915_min_freq_get(void *data, u64 *val) return ret; if (IS_VALLEYVIEW(dev)) - *val = vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.min_delay); + *val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay); else *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -2907,7 +3071,7 @@ i915_min_freq_set(void *data, u64 val) * Turbo will still be enabled, but won't go below the set value. */ if (IS_VALLEYVIEW(dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); dev_priv->rps.min_delay = val; valleyview_set_rps(dev, val); } else { @@ -2938,8 +3102,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; @@ -2960,6 +3127,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 */ @@ -2968,6 +3136,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; } @@ -2983,7 +3152,8 @@ static int i915_forcewake_open(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; - gen6_gt_force_wake_get(dev_priv); + intel_runtime_pm_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); return 0; } @@ -2996,7 +3166,8 @@ static int i915_forcewake_release(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3016,8 +3187,8 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) S_IRUSR, root, dev, &i915_forcewake_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); } @@ -3034,8 +3205,8 @@ static int i915_debugfs_create(struct dentry *root, S_IRUGO | S_IWUSR, root, dev, fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + if (!ent) + return -ENOMEM; return drm_add_fake_info_node(minor, ent, fops); } @@ -3079,6 +3250,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_pc8_status", i915_pc8_status, 0}, + {"i915_power_domain_info", i915_power_domain_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) @@ -3102,10 +3274,10 @@ static const struct i915_debugfs_files { void intel_display_crc_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; + enum pipe pipe; - for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i]; + for_each_pipe(pipe) { + struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; pipe_crc->opened = false; spin_lock_init(&pipe_crc->lock); @@ -3164,5 +3336,3 @@ void i915_debugfs_cleanup(struct drm_minor *minor) drm_debugfs_remove_files(info_list, 1, minor); } } - -#endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 5c648425c1e0..35542eaabe89 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]) @@ -1411,7 +1413,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } -#ifdef CONFIG_DRM_I915_FBDEV +#if IS_ENABLED(CONFIG_FB) static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) { struct apertures_struct *ap; @@ -1494,7 +1496,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); - spin_lock_init(&dev_priv->backlight.lock); + spin_lock_init(&dev_priv->backlight_lock); spin_lock_init(&dev_priv->uncore.lock); spin_lock_init(&dev_priv->mm.object_stat_lock); mutex_init(&dev_priv->dpio_lock); @@ -1639,8 +1641,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_gem_unload; } - if (HAS_POWER_WELL(dev)) - intel_power_domains_init(dev); + intel_power_domains_init(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = i915_load_modeset_init(dev); @@ -1664,11 +1665,12 @@ 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: - if (HAS_POWER_WELL(dev)) - intel_power_domains_remove(dev); + intel_power_domains_remove(dev); drm_vblank_cleanup(dev); out_gem_unload: if (dev_priv->mm.inactive_shrinker.scan_objects) @@ -1704,25 +1706,27 @@ 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(); - if (HAS_POWER_WELL(dev)) { - /* The i915.ko module is still not prepared to be loaded when - * the power well is not enabled, so just enable it in case - * we're going to unload/reload. */ - intel_display_set_init_power(dev, true); - intel_power_domains_remove(dev); - } + /* The i915.ko module is still not prepared to be loaded when + * the power well is not enabled, so just enable it in case + * we're going to unload/reload. */ + intel_display_set_init_power(dev, true); + intel_power_domains_remove(dev); i915_teardown_sysfs(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); @@ -1777,7 +1781,6 @@ int i915_driver_unload(struct drm_device *dev) list_del(&dev_priv->gtt.base.global_link); WARN_ON(!list_empty(&dev_priv->vm_list)); - drm_mm_takedown(&dev_priv->gtt.base.mm); drm_vblank_cleanup(dev); @@ -1910,6 +1913,7 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5b7b7e06cb3a..bb27f0dde03d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -114,7 +114,7 @@ MODULE_PARM_DESC(enable_hangcheck, "(default: true)"); int i915_enable_ppgtt __read_mostly = -1; -module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600); +module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400); MODULE_PARM_DESC(i915_enable_ppgtt, "Enable PPGTT (default: true)"); @@ -155,7 +155,6 @@ MODULE_PARM_DESC(prefault_disable, "Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only."); static struct drm_driver driver; -extern int intel_agp_enabled; static const struct intel_device_info intel_i830_info = { .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, @@ -173,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, }; @@ -192,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 = { @@ -204,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, }; @@ -265,6 +267,7 @@ static const struct intel_device_info intel_ironlake_m_info = { static const struct intel_device_info intel_sandybridge_d_info = { .gen = 6, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, + .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .has_llc = 1, }; @@ -280,6 +283,7 @@ static const struct intel_device_info intel_sandybridge_m_info = { #define GEN7_FEATURES \ .gen = 7, .num_pipes = 3, \ .need_gfx_hws = 1, .has_hotplug = 1, \ + .has_fbc = 1, \ .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \ .has_llc = 1 @@ -292,7 +296,6 @@ static const struct intel_device_info intel_ivybridge_m_info = { GEN7_FEATURES, .is_ivybridge = 1, .is_mobile = 1, - .has_fbc = 1, }; static const struct intel_device_info intel_ivybridge_q_info = { @@ -307,6 +310,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_fbc = 0, /* legal, last one wins */ .has_llc = 0, /* legal, last one wins */ }; @@ -315,6 +319,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_fbc = 0, /* legal, last one wins */ .has_llc = 0, /* legal, last one wins */ }; @@ -332,7 +337,6 @@ static const struct intel_device_info intel_haswell_m_info = { .is_mobile = 1, .has_ddi = 1, .has_fpga_dbg = 1, - .has_fbc = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, }; @@ -476,12 +480,12 @@ check_next: bool i915_semaphore_is_enabled(struct drm_device *dev) { if (INTEL_INFO(dev)->gen < 6) - return 0; + return false; /* Until we get further testing... */ if (IS_GEN8(dev)) { WARN_ON(!i915_preliminary_hw_support); - return 0; + return false; } if (i915_semaphores >= 0) @@ -493,7 +497,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return false; #endif - return 1; + return true; } static int i915_drm_freeze(struct drm_device *dev) @@ -501,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 +694,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; } @@ -762,14 +770,14 @@ int i915_reset(struct drm_device *dev) DRM_INFO("Simulated gpu hang, resetting stop_rings\n"); dev_priv->gpu_error.stop_rings = 0; if (ret == -ENODEV) { - DRM_ERROR("Reset not implemented, but ignoring " - "error for simulated gpu hangs\n"); + DRM_INFO("Reset not implemented, but ignoring " + "error for simulated gpu hangs\n"); ret = 0; } } if (ret) { - DRM_ERROR("Failed to reset chip.\n"); + DRM_ERROR("Failed to reset chip: %i\n", ret); mutex_unlock(&dev->struct_mutex); return ret; } @@ -790,12 +798,9 @@ int i915_reset(struct drm_device *dev) */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->ums.mm_suspended) { - bool hw_contexts_disabled = dev_priv->hw_contexts_disabled; dev_priv->ums.mm_suspended = 0; ret = i915_gem_init_hw(dev); - if (!hw_contexts_disabled && dev_priv->hw_contexts_disabled) - DRM_ERROR("HW contexts didn't survive reset\n"); mutex_unlock(&dev->struct_mutex); if (ret) { DRM_ERROR("Failed hw init on reset %d\n", ret); @@ -831,17 +836,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (PCI_FUNC(pdev->devfn)) return -ENODEV; - /* We've managed to ship a kms-enabled ddx that shipped with an XvMC - * implementation for gen3 (and only gen3) that used legacy drm maps - * (gasp!) to share buffers between X and the client. Hence we need to - * keep around the fake agp stuff for gen3, even when kms is enabled. */ - if (intel_info->gen != 3) { - driver.driver_features &= - ~(DRIVER_USE_AGP | DRIVER_REQUIRE_AGP); - } else if (!intel_agp_enabled) { - DRM_ERROR("drm/i915 can't work without intel_agp module!\n"); - return -ENODEV; - } + driver.driver_features &= ~(DRIVER_USE_AGP | DRIVER_REQUIRE_AGP); return drm_get_pci_dev(pdev, ent, &driver); } @@ -915,6 +910,41 @@ 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"); + + i915_gem_release_all_mmaps(dev_priv); + + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); + 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, @@ -922,6 +952,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 = { @@ -1024,14 +1056,24 @@ static int __init i915_init(void) driver.driver_features &= ~DRIVER_MODESET; #endif - if (!(driver.driver_features & DRIVER_MODESET)) + if (!(driver.driver_features & DRIVER_MODESET)) { driver.get_vblank_timestamp = NULL; +#ifndef CONFIG_DRM_I915_UMS + /* Silently fail loading to not upset userspace. */ + return 0; +#endif + } return drm_pci_init(&driver, &i915_pci_driver); } static void __exit i915_exit(void) { +#ifndef CONFIG_DRM_I915_UMS + if (!(driver.driver_features & DRIVER_MODESET)) + return; /* Never loaded a driver. */ +#endif + drm_pci_exit(&driver, &i915_pci_driver); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 90fcccba17b0..ff6f870d6621 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -89,6 +89,18 @@ enum port { }; #define port_name(p) ((p) + 'A') +#define I915_NUM_PHYS_VLV 1 + +enum dpio_channel { + DPIO_CH0, + DPIO_CH1 +}; + +enum dpio_phy { + DPIO_PHY0, + DPIO_PHY1 +}; + enum intel_display_power_domain { POWER_DOMAIN_PIPE_A, POWER_DOMAIN_PIPE_B, @@ -101,6 +113,7 @@ enum intel_display_power_domain { POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_EDP, POWER_DOMAIN_VGA, + POWER_DOMAIN_AUDIO, POWER_DOMAIN_INIT, POWER_DOMAIN_NUM, @@ -310,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]; @@ -351,6 +364,7 @@ struct drm_i915_error_state { enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS]; }; +struct intel_connector; struct intel_crtc_config; struct intel_crtc; struct intel_limit; @@ -358,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); @@ -413,11 +427,20 @@ struct drm_i915_display_funcs { /* render clock increase/decrease */ /* display clock increase/decrease */ /* pll clock increase/decrease */ + + int (*setup_backlight)(struct intel_connector *connector); + uint32_t (*get_backlight)(struct intel_connector *connector); + void (*set_backlight)(struct intel_connector *connector, + uint32_t level); + void (*disable_backlight)(struct intel_connector *connector); + void (*enable_backlight)(struct intel_connector *connector); }; struct intel_uncore_funcs { - void (*force_wake_get)(struct drm_i915_private *dev_priv); - void (*force_wake_put)(struct drm_i915_private *dev_priv); + void (*force_wake_get)(struct drm_i915_private *dev_priv, + int fw_engine); + void (*force_wake_put)(struct drm_i915_private *dev_priv, + int fw_engine); uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace); uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace); @@ -442,6 +465,9 @@ struct intel_uncore { unsigned fifo_count; unsigned forcewake_count; + unsigned fw_rendercount; + unsigned fw_mediacount; + struct delayed_work force_wake_work; }; @@ -669,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 { @@ -708,7 +733,6 @@ enum intel_sbi_destination { #define QUIRK_PIPEA_FORCE (1<<0) #define QUIRK_LVDS_SSC_DISABLE (1<<1) #define QUIRK_INVERT_BRIGHTNESS (1<<2) -#define QUIRK_NO_PCH_PWM_ENABLE (1<<3) struct intel_fbdev; struct intel_fbc_work; @@ -761,8 +785,6 @@ struct i915_suspend_saved_registers { u32 saveBLC_PWM_CTL; u32 saveBLC_PWM_CTL2; u32 saveBLC_HIST_CTL_B; - u32 saveBLC_PWM_CTL_B; - u32 saveBLC_PWM_CTL2_B; u32 saveBLC_CPU_PWM_CTL; u32 saveBLC_CPU_PWM_CTL2; u32 saveFPB0; @@ -932,21 +954,29 @@ struct intel_ilk_power_mgmt { /* Power well structure for haswell */ struct i915_power_well { + const char *name; + bool always_on; /* power well enable/disable usage count */ int count; + unsigned long domains; + void *data; + void (*set)(struct drm_device *dev, struct i915_power_well *power_well, + bool enable); + bool (*is_enabled)(struct drm_device *dev, + struct i915_power_well *power_well); }; -#define I915_MAX_POWER_WELLS 1 - struct i915_power_domains { /* * Power wells needed for initialization at driver init and suspend * time are on. They are kept on until after the first modeset. */ bool init_power_on; + int power_well_count; struct mutex lock; - struct i915_power_well power_wells[I915_MAX_POWER_WELLS]; + int domain_use_count[POWER_DOMAIN_NUM]; + struct i915_power_well *power_wells; }; struct i915_dri1_state { @@ -1077,34 +1107,30 @@ struct i915_gpu_error { unsigned long missed_irq_rings; /** - * State variable and reset counter controlling the reset flow + * State variable controlling the reset flow and count * - * Upper bits are for the reset counter. This counter is used by the - * wait_seqno code to race-free noticed that a reset event happened and - * that it needs to restart the entire ioctl (since most likely the - * seqno it waited for won't ever signal anytime soon). + * This is a counter which gets incremented when reset is triggered, + * and again when reset has been handled. So odd values (lowest bit set) + * means that reset is in progress and even values that + * (reset_counter >> 1):th reset was successfully completed. + * + * If reset is not completed succesfully, the I915_WEDGE bit is + * set meaning that hardware is terminally sour and there is no + * recovery. All waiters on the reset_queue will be woken when + * that happens. + * + * This counter is used by the wait_seqno code to notice that reset + * event happened and it needs to restart the entire ioctl (since most + * likely the seqno it waited for won't ever signal anytime soon). * * This is important for lock-free wait paths, where no contended lock * naturally enforces the correct ordering between the bail-out of the * waiter and the gpu reset work code. - * - * Lowest bit controls the reset state machine: Set means a reset is in - * progress. This state will (presuming we don't have any bugs) decay - * into either unset (successful reset) or the special WEDGED value (hw - * terminally sour). All waiters on the reset_queue will be woken when - * that happens. */ atomic_t reset_counter; - /** - * Special values/flags for reset_counter - * - * Note that the code relies on - * I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG - * being true. - */ #define I915_RESET_IN_PROGRESS_FLAG 1 -#define I915_WEDGED 0xffffffff +#define I915_WEDGED (1 << 31) /** * Waitqueue to signal when the reset has completed. Used by clients @@ -1158,6 +1184,11 @@ struct intel_vbt_data { int edp_bpp; struct edp_power_seq edp_pps; + struct { + u16 pwm_freq_hz; + bool active_low_pwm; + } backlight; + /* MIPI DSI */ struct { u16 panel_id; @@ -1184,7 +1215,7 @@ struct intel_wm_level { uint32_t fbc_val; }; -struct hsw_wm_values { +struct ilk_wm_values { uint32_t wm_pipe[3]; uint32_t wm_lp[3]; uint32_t wm_lp_spr[3]; @@ -1262,6 +1293,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, @@ -1366,15 +1401,9 @@ typedef struct drm_i915_private { /* overlay */ struct intel_overlay *overlay; - unsigned int sprite_scaling_enabled; - /* backlight */ - struct { - int level; - bool enabled; - spinlock_t lock; /* bl registers and the above bl fields */ - struct backlight_device *device; - } backlight; + /* backlight registers and fields in struct intel_panel */ + spinlock_t backlight_lock; /* LVDS info */ bool no_aux_handshake; @@ -1426,6 +1455,7 @@ typedef struct drm_i915_private { int num_shared_dpll; struct intel_shared_dpll shared_dplls[I915_NUM_PLLS]; struct intel_ddi_plls ddi_plls; + int dpio_phy_iosf_port[I915_NUM_PHYS_VLV]; /* Reclocking support */ bool render_reclock_avail; @@ -1470,7 +1500,6 @@ typedef struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; - bool hw_contexts_disabled; uint32_t hw_context_size; struct list_head context_list; @@ -1492,11 +1521,13 @@ typedef struct drm_i915_private { uint16_t cur_latency[5]; /* current hardware state */ - struct hsw_wm_values hw; + struct ilk_wm_values hw; } wm; 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; @@ -1813,15 +1844,15 @@ struct drm_i915_file_private { #define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2) #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) -#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) +#define HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) #define HAS_IPS(dev) (IS_ULT(dev) || IS_BROADWELL(dev)) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) -#define HAS_POWER_WELL(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #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) (IS_HASWELL(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 @@ -1911,7 +1942,6 @@ extern void intel_hpd_init(struct drm_device *dev); extern void intel_uncore_sanitize(struct drm_device *dev); extern void intel_uncore_early_sanitize(struct drm_device *dev); extern void intel_uncore_init(struct drm_device *dev); -extern void intel_uncore_clear_errors(struct drm_device *dev); extern void intel_uncore_check_errors(struct drm_device *dev); extern void intel_uncore_fini(struct drm_device *dev); @@ -1987,6 +2017,7 @@ void i915_gem_object_unpin(struct drm_i915_gem_object *obj); int __must_check i915_vma_unbind(struct i915_vma *vma); int __must_check i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj); int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); +void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); @@ -2063,12 +2094,17 @@ int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, static inline bool i915_reset_in_progress(struct i915_gpu_error *error) { return unlikely(atomic_read(&error->reset_counter) - & I915_RESET_IN_PROGRESS_FLAG); + & (I915_RESET_IN_PROGRESS_FLAG | I915_WEDGED)); } static inline bool i915_terminally_wedged(struct i915_gpu_error *error) { - return atomic_read(&error->reset_counter) == I915_WEDGED; + return atomic_read(&error->reset_counter) & I915_WEDGED; +} + +static inline u32 i915_reset_count(struct i915_gpu_error *error) +{ + return ((atomic_read(&error->reset_counter) & ~I915_WEDGED) + 1) / 2; } void i915_gem_reset(struct drm_device *dev); @@ -2180,7 +2216,7 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj, } /* i915_gem_context.c */ -void i915_gem_context_init(struct drm_device *dev); +int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, @@ -2398,6 +2434,8 @@ extern int intel_enable_rc6(const struct drm_device *dev); extern bool i915_semaphore_is_enabled(struct drm_device *dev); int i915_reg_read_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); /* overlay */ extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); @@ -2413,8 +2451,8 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, * must be set to prevent GT core from power down and stale values being * returned. */ -void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); -void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine); +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); @@ -2429,6 +2467,8 @@ u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); +u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg); +void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg); void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg); @@ -2437,9 +2477,30 @@ 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); + +void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine); +void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine); + +#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \ + (((reg) >= 0x2000 && (reg) < 0x4000) ||\ + ((reg) >= 0x5000 && (reg) < 0x8000) ||\ + ((reg) >= 0xB000 && (reg) < 0x12000) ||\ + ((reg) >= 0x2E000 && (reg) < 0x30000)) + +#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\ + (((reg) >= 0x12000 && (reg) < 0x14000) ||\ + ((reg) >= 0x22000 && (reg) < 0x24000) ||\ + ((reg) >= 0x30000 && (reg) < 0x40000)) + +#define FORCEWAKE_RENDER (1 << 0) +#define FORCEWAKE_MEDIA (1 << 1) +#define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA) -int vlv_gpu_freq(int ddr_freq, int val); -int vlv_freq_opcode(int ddr_freq, int val); #define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true) #define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 76d3d1ab73c6..32636a470367 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,38 @@ 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; +} + +void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv) +{ + struct i915_vma *vma; + + /* + * Only the global gtt is relevant for gtt memory mappings, so restrict + * list traversal to objects bound into the global address space. Note + * that the active list should be empty, but better safe than sorry. + */ + WARN_ON(!list_empty(&dev_priv->gtt.base.active_list)); + list_for_each_entry(vma, &dev_priv->gtt.base.active_list, mm_list) + i915_gem_release_mmap(vma->obj); + list_for_each_entry(vma, &dev_priv->gtt.base.inactive_list, mm_list) + i915_gem_release_mmap(vma->obj); } /** @@ -2760,7 +2787,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. */ @@ -2768,7 +2794,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 @@ -2776,6 +2801,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; } @@ -4179,6 +4210,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) @@ -4223,6 +4256,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, @@ -4479,7 +4514,13 @@ i915_gem_init_hw(struct drm_device *dev) * XXX: There was some w/a described somewhere suggesting loading * contexts before PPGTT. */ - i915_gem_context_init(dev); + ret = i915_gem_context_init(dev); + if (ret) { + i915_gem_cleanup_ringbuffer(dev); + DRM_ERROR("Context initialization failed %d\n", ret); + return ret; + } + if (dev_priv->mm.aliasing_ppgtt) { ret = dev_priv->mm.aliasing_ppgtt->enable(dev); if (ret) { diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index b0f42b9ca037..e08acaba5402 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -247,36 +247,34 @@ err_destroy: return ret; } -void i915_gem_context_init(struct drm_device *dev) +int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int ret; - if (!HAS_HW_CONTEXTS(dev)) { - dev_priv->hw_contexts_disabled = true; - DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n"); - return; - } + if (!HAS_HW_CONTEXTS(dev)) + return 0; /* If called from reset, or thaw... we've been here already */ - if (dev_priv->hw_contexts_disabled || - dev_priv->ring[RCS].default_context) - return; + if (dev_priv->ring[RCS].default_context) + return 0; dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); if (dev_priv->hw_context_size > (1<<20)) { - dev_priv->hw_contexts_disabled = true; DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n"); - return; + return -E2BIG; } - if (create_default_context(dev_priv)) { - dev_priv->hw_contexts_disabled = true; - DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n"); - return; + ret = create_default_context(dev_priv); + if (ret) { + DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n", + ret); + return ret; } DRM_DEBUG_DRIVER("HW context support initialized\n"); + return 0; } void i915_gem_context_fini(struct drm_device *dev) @@ -284,7 +282,7 @@ void i915_gem_context_fini(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context; - if (dev_priv->hw_contexts_disabled) + if (!HAS_HW_CONTEXTS(dev)) return; /* The only known way to stop the gpu from accessing the hw context is @@ -327,16 +325,16 @@ i915_gem_context_get_hang_stats(struct drm_device *dev, struct drm_file *file, u32 id) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_file_private *file_priv = file->driver_priv; struct i915_hw_context *ctx; if (id == DEFAULT_CONTEXT_ID) return &file_priv->hang_stats; - ctx = NULL; - if (!dev_priv->hw_contexts_disabled) - ctx = i915_gem_context_get(file->driver_priv, id); + if (!HAS_HW_CONTEXTS(dev)) + return ERR_PTR(-ENOENT); + + ctx = i915_gem_context_get(file->driver_priv, id); if (ctx == NULL) return ERR_PTR(-ENOENT); @@ -502,8 +500,6 @@ static int do_switch(struct i915_hw_context *to) * @ring: ring for which we'll execute the context switch * @file_priv: file_priv associated with the context, may be NULL * @id: context id number - * @seqno: sequence number by which the new context will be switched to - * @flags: * * The context life cycle is simple. The context refcount is incremented and * decremented by 1 and create and destroy. If the context is in use by the GPU, @@ -517,7 +513,7 @@ int i915_switch_context(struct intel_ring_buffer *ring, struct drm_i915_private *dev_priv = ring->dev->dev_private; struct i915_hw_context *to; - if (dev_priv->hw_contexts_disabled) + if (!HAS_HW_CONTEXTS(ring->dev)) return 0; WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); @@ -542,7 +538,6 @@ int i915_switch_context(struct intel_ring_buffer *ring, int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_context_create *args = data; struct drm_i915_file_private *file_priv = file->driver_priv; struct i915_hw_context *ctx; @@ -551,7 +546,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - if (dev_priv->hw_contexts_disabled) + if (!HAS_HW_CONTEXTS(dev)) return -ENODEV; ret = i915_mutex_lock_interruptible(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a3ba9a8cd687..8d795626a25e 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -46,7 +46,7 @@ struct eb_vmas { }; static struct eb_vmas * -eb_create(struct drm_i915_gem_execbuffer2 *args, struct i915_address_space *vm) +eb_create(struct drm_i915_gem_execbuffer2 *args) { struct eb_vmas *eb = NULL; @@ -344,7 +344,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, target_i915_obj = target_vma->obj; target_obj = &target_vma->obj->base; - target_offset = i915_gem_obj_ggtt_offset(target_i915_obj); + target_offset = target_vma->node.start; /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and * pipe_control writes because the gpu doesn't properly redirect them @@ -491,8 +491,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma, } static int -i915_gem_execbuffer_relocate(struct eb_vmas *eb, - struct i915_address_space *vm) +i915_gem_execbuffer_relocate(struct eb_vmas *eb) { struct i915_vma *vma; int ret = 0; @@ -901,6 +900,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) @@ -980,8 +997,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; @@ -1108,6 +1124,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; @@ -1118,7 +1136,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - eb = eb_create(args, vm); + 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); ret = -ENOMEM; @@ -1141,7 +1165,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* The objects are in their final locations, apply the relocations. */ if (need_relocs) - ret = i915_gem_execbuffer_relocate(eb, vm); + ret = i915_gem_execbuffer_relocate(eb); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, @@ -1170,17 +1194,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; @@ -1242,6 +1255,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_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d3c3b5b15824..6c3a6e60aeac 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -240,10 +240,16 @@ static int gen8_ppgtt_enable(struct drm_device *dev) for_each_ring(ring, dev_priv, j) { ret = gen8_write_pdp(ring, i, addr); if (ret) - return ret; + goto err_out; } } return 0; + +err_out: + for_each_ring(ring, dev_priv, j) + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE)); + return ret; } static void gen8_ppgtt_clear_range(struct i915_address_space *vm, @@ -293,23 +299,23 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE; struct sg_page_iter sg_iter; - pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]); + pt_vaddr = NULL; for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { - dma_addr_t page_addr; + if (pt_vaddr == NULL) + pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]); - page_addr = sg_dma_address(sg_iter.sg) + - (sg_iter.sg_pgoffset << PAGE_SHIFT); - pt_vaddr[act_pte] = gen8_pte_encode(page_addr, cache_level, - true); + pt_vaddr[act_pte] = + gen8_pte_encode(sg_page_iter_dma_address(&sg_iter), + cache_level, true); if (++act_pte == GEN8_PTES_PER_PAGE) { kunmap_atomic(pt_vaddr); + pt_vaddr = NULL; act_pt++; - pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]); act_pte = 0; - } } - kunmap_atomic(pt_vaddr); + if (pt_vaddr) + kunmap_atomic(pt_vaddr); } static void gen8_ppgtt_cleanup(struct i915_address_space *vm) @@ -318,6 +324,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) container_of(vm, struct i915_hw_ppgtt, base); int i, j; + drm_mm_takedown(&vm->mm); + for (i = 0; i < ppgtt->num_pd_pages ; i++) { if (ppgtt->pd_dma_addr[i]) { pci_unmap_page(ppgtt->base.dev->pdev, @@ -381,6 +389,8 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) ppgtt->base.clear_range = gen8_ppgtt_clear_range; ppgtt->base.insert_entries = gen8_ppgtt_insert_entries; ppgtt->base.cleanup = gen8_ppgtt_cleanup; + ppgtt->base.start = 0; + ppgtt->base.total = ppgtt->num_pt_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE; BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS); @@ -573,21 +583,23 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; struct sg_page_iter sg_iter; - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); + pt_vaddr = NULL; for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { - dma_addr_t page_addr; + if (pt_vaddr == NULL) + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); - page_addr = sg_page_iter_dma_address(&sg_iter); - pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level, true); + pt_vaddr[act_pte] = + vm->pte_encode(sg_page_iter_dma_address(&sg_iter), + cache_level, true); if (++act_pte == I915_PPGTT_PT_ENTRIES) { kunmap_atomic(pt_vaddr); + pt_vaddr = NULL; act_pt++; - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); act_pte = 0; - } } - kunmap_atomic(pt_vaddr); + if (pt_vaddr) + kunmap_atomic(pt_vaddr); } static void gen6_ppgtt_cleanup(struct i915_address_space *vm) @@ -632,6 +644,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.cleanup = gen6_ppgtt_cleanup; ppgtt->base.scratch = dev_priv->gtt.base.scratch; + ppgtt->base.start = 0; + ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE; ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *), GFP_KERNEL); if (!ppgtt->pt_pages) @@ -1124,7 +1138,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, if (ret) DRM_DEBUG_KMS("Reservation failed\n"); obj->has_global_gtt_mapping = 1; - list_add(&vma->vma_link, &obj->vma_list); } dev_priv->gtt.base.start = start; @@ -1400,6 +1413,8 @@ static void gen6_gmch_remove(struct i915_address_space *vm) { struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); + + drm_mm_takedown(&vm->mm); iounmap(gtt->gsm); teardown_scratch_page(vm->dev); } @@ -1425,6 +1440,9 @@ static int i915_gmch_probe(struct drm_device *dev, dev_priv->gtt.base.clear_range = i915_ggtt_clear_range; dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries; + if (unlikely(dev_priv->gtt.do_idle_maps)) + DRM_INFO("applying Ironlake quirks for intel_iommu\n"); + return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index d284d892ed94..fed87ec17211 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -420,6 +420,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, list_add_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&vma->mm_list, &ggtt->inactive_list); + i915_gem_object_pin_pages(obj); return obj; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 79dcb8f896c6..a707cca692e4 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 f13d5edc39d5..6d11e253218a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -62,7 +62,7 @@ static const u32 hpd_mask_i915[] = { [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN }; -static const u32 hpd_status_gen4[] = { +static const u32 hpd_status_g4x[] = { [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, @@ -600,7 +600,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) * Cook up a vblank counter by also checking the pixel * counter against vblank start. */ - return ((high1 << 8) | low) + (pixel >= vbl_start); + return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff; } static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) @@ -1015,10 +1015,8 @@ static void gen6_pm_rps_work(struct work_struct *work) /* sysfs frequency interfaces may have snuck in while servicing the * interrupt */ - if (new_delay < (int)dev_priv->rps.min_delay) - new_delay = dev_priv->rps.min_delay; - if (new_delay > (int)dev_priv->rps.max_delay) - new_delay = dev_priv->rps.max_delay; + new_delay = clamp_t(int, new_delay, + dev_priv->rps.min_delay, dev_priv->rps.max_delay); dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay; if (IS_VALLEYVIEW(dev_priv->dev)) @@ -1235,9 +1233,10 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { - WARN(((hpd[i] & hotplug_trigger) && - dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED), - "Received HPD interrupt although disabled\n"); + WARN_ONCE(hpd[i] & hotplug_trigger && + dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED, + "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", + hotplug_trigger, i, hpd[i]); if (!(hpd[i] & hotplug_trigger) || dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) @@ -1474,6 +1473,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -1993,7 +1995,7 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, reset_done_event); } else { - atomic_set(&error->reset_counter, I915_WEDGED); + atomic_set_mask(I915_WEDGED, &error->reset_counter); } /* @@ -3140,10 +3142,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; @@ -3151,7 +3153,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 @@ -3220,9 +3222,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 (HAS_FBC(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); @@ -3418,7 +3424,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) for_each_pipe(pipe) { int plane = pipe; - if (IS_MOBILE(dev)) + if (HAS_FBC(dev)) plane = !plane; if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && @@ -3655,7 +3661,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) hotplug_status); intel_hpd_irq_handler(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); + IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915); + + if (IS_G4X(dev) && + (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)) + dp_aux_irq_handler(dev); I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); @@ -3893,8 +3903,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); @@ -3908,34 +3918,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 ee2742122a02..76126e0ae609 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -193,10 +193,13 @@ #define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ #define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ +#define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) +#define MI_ARB_ENABLE (1<<0) +#define MI_ARB_DISABLE (0<<0) #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) #define MI_SUSPEND_FLUSH_EN (1<<0) -#define MI_REPORT_HEAD MI_INSTR(0x07, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) #define MI_OVERLAY_CONTINUE (0x0<<21) #define MI_OVERLAY_ON (0x1<<21) @@ -212,10 +215,24 @@ #define MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19) #define MI_DISPLAY_FLIP_IVB_PLANE_C (4 << 19) #define MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19) -#define MI_ARB_ON_OFF MI_INSTR(0x08, 0) -#define MI_ARB_ENABLE (1<<0) -#define MI_ARB_DISABLE (0<<0) - +#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ +#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) +#define MI_SEMAPHORE_UPDATE (1<<21) +#define MI_SEMAPHORE_COMPARE (1<<20) +#define MI_SEMAPHORE_REGISTER (1<<18) +#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ +#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ +#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ +#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ +#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ +#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ +#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ +#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ +#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ +#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ +#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ +#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ +#define MI_SEMAPHORE_SYNC_INVALID (3<<16) #define MI_SET_CONTEXT MI_INSTR(0x18, 0) #define MI_MM_SPACE_GTT (1<<8) #define MI_MM_SPACE_PHYSICAL (0<<8) @@ -235,7 +252,7 @@ */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1) -#define MI_SRM_LRM_GLOBAL_GTT (1<<22) +#define MI_SRM_LRM_GLOBAL_GTT (1<<22) #define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ #define MI_FLUSH_DW_STORE_INDEX (1<<21) #define MI_INVALIDATE_TLB (1<<18) @@ -246,30 +263,13 @@ #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) /* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ -#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_BATCH_PPGTT_HSW (1<<8) -#define MI_BATCH_NON_SECURE_HSW (1<<13) +#define MI_BATCH_NON_SECURE_HSW (1<<13) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) #define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) -#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ -#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) -#define MI_SEMAPHORE_UPDATE (1<<21) -#define MI_SEMAPHORE_COMPARE (1<<20) -#define MI_SEMAPHORE_REGISTER (1<<18) -#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ -#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ -#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ -#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ -#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ -#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ -#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ -#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ -#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ -#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ -#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ -#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ -#define MI_SEMAPHORE_SYNC_INVALID (3<<16) + #define MI_PREDICATE_RESULT_2 (0x2214) #define LOWER_SLICE_ENABLED (1<<0) @@ -354,6 +354,7 @@ #define IOSF_BYTE_ENABLES_SHIFT 4 #define IOSF_BAR_SHIFT 1 #define IOSF_SB_BUSY (1<<0) +#define IOSF_PORT_BUNIT 0x3 #define IOSF_PORT_PUNIT 0x4 #define IOSF_PORT_NC 0x11 #define IOSF_PORT_DPIO 0x12 @@ -361,12 +362,21 @@ #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) +/* See configdb bunit SB addr map */ +#define BUNIT_REG_BISOC 0x11 + #define PUNIT_OPCODE_REG_READ 6 #define PUNIT_OPCODE_REG_WRITE 7 +#define PUNIT_REG_DSPFREQ 0x36 +#define DSPFREQSTAT_SHIFT 30 +#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) +#define DSPFREQGUAR_SHIFT 14 +#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) #define PUNIT_REG_PWRGT_CTRL 0x60 #define PUNIT_REG_PWRGT_STATUS 0x61 #define PUNIT_CLK_GATE 1 @@ -429,6 +439,7 @@ #define DSI_PLL_N1_DIV_MASK (3 << 16) #define DSI_PLL_M1_DIV_SHIFT 0 #define DSI_PLL_M1_DIV_MASK (0x1ff << 0) +#define CCK_DISPLAY_CLOCK_CONTROL 0x6b /* * DPIO - a special bus for various display related registers to hide behind @@ -447,15 +458,13 @@ #define DPIO_SFR_BYPASS (1<<1) #define DPIO_CMNRST (1<<0) -#define _DPIO_TX3_SWING_CTL4_A 0x690 -#define _DPIO_TX3_SWING_CTL4_B 0x2a90 -#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX3_SWING_CTL4_A, \ - _DPIO_TX3_SWING_CTL4_B) +#define DPIO_PHY(pipe) ((pipe) >> 1) +#define DPIO_PHY_IOSF_PORT(phy) (dev_priv->dpio_phy_iosf_port[phy]) /* * Per pipe/PLL DPIO regs */ -#define _DPIO_DIV_A 0x800c +#define _VLV_PLL_DW3_CH0 0x800c #define DPIO_POST_DIV_SHIFT (28) /* 3 bits */ #define DPIO_POST_DIV_DAC 0 #define DPIO_POST_DIV_HDMIDP 1 /* DAC 225-400M rate */ @@ -468,10 +477,10 @@ #define DPIO_ENABLE_CALIBRATION (1<<11) #define DPIO_M1DIV_SHIFT (8) /* 3 bits */ #define DPIO_M2DIV_MASK 0xff -#define _DPIO_DIV_B 0x802c -#define DPIO_DIV(pipe) _PIPE(pipe, _DPIO_DIV_A, _DPIO_DIV_B) +#define _VLV_PLL_DW3_CH1 0x802c +#define VLV_PLL_DW3(ch) _PIPE(ch, _VLV_PLL_DW3_CH0, _VLV_PLL_DW3_CH1) -#define _DPIO_REFSFR_A 0x8014 +#define _VLV_PLL_DW5_CH0 0x8014 #define DPIO_REFSEL_OVERRIDE 27 #define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */ #define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */ @@ -479,118 +488,112 @@ #define DPIO_PLL_REFCLK_SEL_MASK 3 #define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */ #define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */ -#define _DPIO_REFSFR_B 0x8034 -#define DPIO_REFSFR(pipe) _PIPE(pipe, _DPIO_REFSFR_A, _DPIO_REFSFR_B) +#define _VLV_PLL_DW5_CH1 0x8034 +#define VLV_PLL_DW5(ch) _PIPE(ch, _VLV_PLL_DW5_CH0, _VLV_PLL_DW5_CH1) -#define _DPIO_CORE_CLK_A 0x801c -#define _DPIO_CORE_CLK_B 0x803c -#define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B) +#define _VLV_PLL_DW7_CH0 0x801c +#define _VLV_PLL_DW7_CH1 0x803c +#define VLV_PLL_DW7(ch) _PIPE(ch, _VLV_PLL_DW7_CH0, _VLV_PLL_DW7_CH1) -#define _DPIO_IREF_CTL_A 0x8040 -#define _DPIO_IREF_CTL_B 0x8060 -#define DPIO_IREF_CTL(pipe) _PIPE(pipe, _DPIO_IREF_CTL_A, _DPIO_IREF_CTL_B) +#define _VLV_PLL_DW8_CH0 0x8040 +#define _VLV_PLL_DW8_CH1 0x8060 +#define VLV_PLL_DW8(ch) _PIPE(ch, _VLV_PLL_DW8_CH0, _VLV_PLL_DW8_CH1) -#define DPIO_IREF_BCAST 0xc044 -#define _DPIO_IREF_A 0x8044 -#define _DPIO_IREF_B 0x8064 -#define DPIO_IREF(pipe) _PIPE(pipe, _DPIO_IREF_A, _DPIO_IREF_B) +#define VLV_PLL_DW9_BCAST 0xc044 +#define _VLV_PLL_DW9_CH0 0x8044 +#define _VLV_PLL_DW9_CH1 0x8064 +#define VLV_PLL_DW9(ch) _PIPE(ch, _VLV_PLL_DW9_CH0, _VLV_PLL_DW9_CH1) -#define _DPIO_PLL_CML_A 0x804c -#define _DPIO_PLL_CML_B 0x806c -#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B) +#define _VLV_PLL_DW10_CH0 0x8048 +#define _VLV_PLL_DW10_CH1 0x8068 +#define VLV_PLL_DW10(ch) _PIPE(ch, _VLV_PLL_DW10_CH0, _VLV_PLL_DW10_CH1) -#define _DPIO_LPF_COEFF_A 0x8048 -#define _DPIO_LPF_COEFF_B 0x8068 -#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B) +#define _VLV_PLL_DW11_CH0 0x804c +#define _VLV_PLL_DW11_CH1 0x806c +#define VLV_PLL_DW11(ch) _PIPE(ch, _VLV_PLL_DW11_CH0, _VLV_PLL_DW11_CH1) -#define DPIO_CALIBRATION 0x80ac +/* Spec for ref block start counts at DW10 */ +#define VLV_REF_DW13 0x80ac -#define DPIO_FASTCLK_DISABLE 0x8100 +#define VLV_CMN_DW0 0x8100 /* * Per DDI channel DPIO regs */ -#define _DPIO_PCS_TX_0 0x8200 -#define _DPIO_PCS_TX_1 0x8400 +#define _VLV_PCS_DW0_CH0 0x8200 +#define _VLV_PCS_DW0_CH1 0x8400 #define DPIO_PCS_TX_LANE2_RESET (1<<16) #define DPIO_PCS_TX_LANE1_RESET (1<<7) -#define DPIO_PCS_TX(port) _PORT(port, _DPIO_PCS_TX_0, _DPIO_PCS_TX_1) +#define VLV_PCS_DW0(ch) _PORT(ch, _VLV_PCS_DW0_CH0, _VLV_PCS_DW0_CH1) -#define _DPIO_PCS_CLK_0 0x8204 -#define _DPIO_PCS_CLK_1 0x8404 +#define _VLV_PCS_DW1_CH0 0x8204 +#define _VLV_PCS_DW1_CH1 0x8404 #define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1<<22) #define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21) #define DPIO_PCS_CLK_DATAWIDTH_SHIFT (6) #define DPIO_PCS_CLK_SOFT_RESET (1<<5) -#define DPIO_PCS_CLK(port) _PORT(port, _DPIO_PCS_CLK_0, _DPIO_PCS_CLK_1) - -#define _DPIO_PCS_CTL_OVR1_A 0x8224 -#define _DPIO_PCS_CTL_OVR1_B 0x8424 -#define DPIO_PCS_CTL_OVER1(port) _PORT(port, _DPIO_PCS_CTL_OVR1_A, \ - _DPIO_PCS_CTL_OVR1_B) - -#define _DPIO_PCS_STAGGER0_A 0x822c -#define _DPIO_PCS_STAGGER0_B 0x842c -#define DPIO_PCS_STAGGER0(port) _PORT(port, _DPIO_PCS_STAGGER0_A, \ - _DPIO_PCS_STAGGER0_B) - -#define _DPIO_PCS_STAGGER1_A 0x8230 -#define _DPIO_PCS_STAGGER1_B 0x8430 -#define DPIO_PCS_STAGGER1(port) _PORT(port, _DPIO_PCS_STAGGER1_A, \ - _DPIO_PCS_STAGGER1_B) - -#define _DPIO_PCS_CLOCKBUF0_A 0x8238 -#define _DPIO_PCS_CLOCKBUF0_B 0x8438 -#define DPIO_PCS_CLOCKBUF0(port) _PORT(port, _DPIO_PCS_CLOCKBUF0_A, \ - _DPIO_PCS_CLOCKBUF0_B) - -#define _DPIO_PCS_CLOCKBUF8_A 0x825c -#define _DPIO_PCS_CLOCKBUF8_B 0x845c -#define DPIO_PCS_CLOCKBUF8(port) _PORT(port, _DPIO_PCS_CLOCKBUF8_A, \ - _DPIO_PCS_CLOCKBUF8_B) - -#define _DPIO_TX_SWING_CTL2_A 0x8288 -#define _DPIO_TX_SWING_CTL2_B 0x8488 -#define DPIO_TX_SWING_CTL2(port) _PORT(port, _DPIO_TX_SWING_CTL2_A, \ - _DPIO_TX_SWING_CTL2_B) - -#define _DPIO_TX_SWING_CTL3_A 0x828c -#define _DPIO_TX_SWING_CTL3_B 0x848c -#define DPIO_TX_SWING_CTL3(port) _PORT(port, _DPIO_TX_SWING_CTL3_A, \ - _DPIO_TX_SWING_CTL3_B) - -#define _DPIO_TX_SWING_CTL4_A 0x8290 -#define _DPIO_TX_SWING_CTL4_B 0x8490 -#define DPIO_TX_SWING_CTL4(port) _PORT(port, _DPIO_TX_SWING_CTL4_A, \ - _DPIO_TX_SWING_CTL4_B) - -#define _DPIO_TX_OCALINIT_0 0x8294 -#define _DPIO_TX_OCALINIT_1 0x8494 +#define VLV_PCS_DW1(ch) _PORT(ch, _VLV_PCS_DW1_CH0, _VLV_PCS_DW1_CH1) + +#define _VLV_PCS_DW8_CH0 0x8220 +#define _VLV_PCS_DW8_CH1 0x8420 +#define VLV_PCS_DW8(ch) _PORT(ch, _VLV_PCS_DW8_CH0, _VLV_PCS_DW8_CH1) + +#define _VLV_PCS01_DW8_CH0 0x0220 +#define _VLV_PCS23_DW8_CH0 0x0420 +#define _VLV_PCS01_DW8_CH1 0x2620 +#define _VLV_PCS23_DW8_CH1 0x2820 +#define VLV_PCS01_DW8(port) _PORT(port, _VLV_PCS01_DW8_CH0, _VLV_PCS01_DW8_CH1) +#define VLV_PCS23_DW8(port) _PORT(port, _VLV_PCS23_DW8_CH0, _VLV_PCS23_DW8_CH1) + +#define _VLV_PCS_DW9_CH0 0x8224 +#define _VLV_PCS_DW9_CH1 0x8424 +#define VLV_PCS_DW9(ch) _PORT(ch, _VLV_PCS_DW9_CH0, _VLV_PCS_DW9_CH1) + +#define _VLV_PCS_DW11_CH0 0x822c +#define _VLV_PCS_DW11_CH1 0x842c +#define VLV_PCS_DW11(ch) _PORT(ch, _VLV_PCS_DW11_CH0, _VLV_PCS_DW11_CH1) + +#define _VLV_PCS_DW12_CH0 0x8230 +#define _VLV_PCS_DW12_CH1 0x8430 +#define VLV_PCS_DW12(ch) _PORT(ch, _VLV_PCS_DW12_CH0, _VLV_PCS_DW12_CH1) + +#define _VLV_PCS_DW14_CH0 0x8238 +#define _VLV_PCS_DW14_CH1 0x8438 +#define VLV_PCS_DW14(ch) _PORT(ch, _VLV_PCS_DW14_CH0, _VLV_PCS_DW14_CH1) + +#define _VLV_PCS_DW23_CH0 0x825c +#define _VLV_PCS_DW23_CH1 0x845c +#define VLV_PCS_DW23(ch) _PORT(ch, _VLV_PCS_DW23_CH0, _VLV_PCS_DW23_CH1) + +#define _VLV_TX_DW2_CH0 0x8288 +#define _VLV_TX_DW2_CH1 0x8488 +#define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1) + +#define _VLV_TX_DW3_CH0 0x828c +#define _VLV_TX_DW3_CH1 0x848c +#define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1) + +#define _VLV_TX_DW4_CH0 0x8290 +#define _VLV_TX_DW4_CH1 0x8490 +#define VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1) + +#define _VLV_TX3_DW4_CH0 0x690 +#define _VLV_TX3_DW4_CH1 0x2a90 +#define VLV_TX3_DW4(ch) _PORT(ch, _VLV_TX3_DW4_CH0, _VLV_TX3_DW4_CH1) + +#define _VLV_TX_DW5_CH0 0x8294 +#define _VLV_TX_DW5_CH1 0x8494 #define DPIO_TX_OCALINIT_EN (1<<31) -#define DPIO_TX_OCALINIT(port) _PORT(port, _DPIO_TX_OCALINIT_0, \ - _DPIO_TX_OCALINIT_1) - -#define _DPIO_TX_CTL_0 0x82ac -#define _DPIO_TX_CTL_1 0x84ac -#define DPIO_TX_CTL(port) _PORT(port, _DPIO_TX_CTL_0, _DPIO_TX_CTL_1) - -#define _DPIO_TX_LANE_0 0x82b8 -#define _DPIO_TX_LANE_1 0x84b8 -#define DPIO_TX_LANE(port) _PORT(port, _DPIO_TX_LANE_0, _DPIO_TX_LANE_1) - -#define _DPIO_DATA_CHANNEL1 0x8220 -#define _DPIO_DATA_CHANNEL2 0x8420 -#define DPIO_DATA_CHANNEL(port) _PORT(port, _DPIO_DATA_CHANNEL1, _DPIO_DATA_CHANNEL2) - -#define _DPIO_PORT0_PCS0 0x0220 -#define _DPIO_PORT0_PCS1 0x0420 -#define _DPIO_PORT1_PCS2 0x2620 -#define _DPIO_PORT1_PCS3 0x2820 -#define DPIO_DATA_LANE_A(port) _PORT(port, _DPIO_PORT0_PCS0, _DPIO_PORT1_PCS2) -#define DPIO_DATA_LANE_B(port) _PORT(port, _DPIO_PORT0_PCS1, _DPIO_PORT1_PCS3) -#define DPIO_DATA_CHANNEL1 0x8220 -#define DPIO_DATA_CHANNEL2 0x8420 +#define VLV_TX_DW5(ch) _PORT(ch, _VLV_TX_DW5_CH0, _VLV_TX_DW5_CH1) + +#define _VLV_TX_DW11_CH0 0x82ac +#define _VLV_TX_DW11_CH1 0x84ac +#define VLV_TX_DW11(ch) _PORT(ch, _VLV_TX_DW11_CH0, _VLV_TX_DW11_CH1) + +#define _VLV_TX_DW14_CH0 0x82b8 +#define _VLV_TX_DW14_CH1 0x84b8 +#define VLV_TX_DW14(ch) _PORT(ch, _VLV_TX_DW14_CH0, _VLV_TX_DW14_CH1) /* * Fence registers @@ -732,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 @@ -922,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) @@ -999,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) @@ -1026,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) @@ -2130,6 +2135,10 @@ #define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) #define CRT_HOTPLUG_MONITOR_MONO (2 << 8) #define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +#define DP_AUX_CHANNEL_D_INT_STATUS_G4X (1 << 6) +#define DP_AUX_CHANNEL_C_INT_STATUS_G4X (1 << 5) +#define DP_AUX_CHANNEL_B_INT_STATUS_G4X (1 << 4) +#define DP_AUX_CHANNEL_MASK_INT_STATUS_G4X (1 << 4) /* SDVO is different across gen3/4 */ #define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) #define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) @@ -3421,42 +3430,6 @@ /* the unit of memory self-refresh latency time is 0.5us */ #define ILK_SRLT_MASK 0x3f -/* define the fifo size on Ironlake */ -#define ILK_DISPLAY_FIFO 128 -#define ILK_DISPLAY_MAXWM 64 -#define ILK_DISPLAY_DFTWM 8 -#define ILK_CURSOR_FIFO 32 -#define ILK_CURSOR_MAXWM 16 -#define ILK_CURSOR_DFTWM 8 - -#define ILK_DISPLAY_SR_FIFO 512 -#define ILK_DISPLAY_MAX_SRWM 0x1ff -#define ILK_DISPLAY_DFT_SRWM 0x3f -#define ILK_CURSOR_SR_FIFO 64 -#define ILK_CURSOR_MAX_SRWM 0x3f -#define ILK_CURSOR_DFT_SRWM 8 - -#define ILK_FIFO_LINE_SIZE 64 - -/* define the WM info on Sandybridge */ -#define SNB_DISPLAY_FIFO 128 -#define SNB_DISPLAY_MAXWM 0x7f /* bit 16:22 */ -#define SNB_DISPLAY_DFTWM 8 -#define SNB_CURSOR_FIFO 32 -#define SNB_CURSOR_MAXWM 0x1f /* bit 4:0 */ -#define SNB_CURSOR_DFTWM 8 - -#define SNB_DISPLAY_SR_FIFO 512 -#define SNB_DISPLAY_MAX_SRWM 0x1ff /* bit 16:8 */ -#define SNB_DISPLAY_DFT_SRWM 0x3f -#define SNB_CURSOR_SR_FIFO 64 -#define SNB_CURSOR_MAX_SRWM 0x3f /* bit 5:0 */ -#define SNB_CURSOR_DFT_SRWM 8 - -#define SNB_FBC_MAX_SRWM 0xf /* bit 23:20 */ - -#define SNB_FIFO_LINE_SIZE 64 - /* the address where we get all kinds of latency value */ #define SSKPD 0x5d10 @@ -3787,7 +3760,7 @@ #define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) #define SP_ENABLE (1<<31) -#define SP_GEAMMA_ENABLE (1<<30) +#define SP_GAMMA_ENABLE (1<<30) #define SP_PIXFORMAT_MASK (0xf<<26) #define SP_FORMAT_YUV422 (0<<26) #define SP_FORMAT_BGR565 (5<<26) @@ -4139,6 +4112,8 @@ #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) +#define DISP_ARB_CTL2 0x45004 +#define DISP_DATA_PARTITION_5_6 (1<<6) #define GEN7_MSG_CTL 0x45010 #define WAIT_FOR_PCH_RESET_ACK (1<<1) #define WAIT_FOR_PCH_FLR_ACK (1<<0) @@ -4159,6 +4134,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) @@ -4843,6 +4822,8 @@ #define FORCEWAKE_ACK 0x130090 #define VLV_GTLC_WAKE_CTRL 0x130090 #define VLV_GTLC_PW_STATUS 0x130094 +#define VLV_GTLC_PW_RENDER_STATUS_MASK 0x80 +#define VLV_GTLC_PW_MEDIA_STATUS_MASK 0x20 #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 @@ -4851,12 +4832,16 @@ #define FORCEWAKE_MT_ENABLE (1<<5) #define GTFIFODBG 0x120000 -#define GT_FIFO_CPU_ERROR_MASK 7 +#define GT_FIFO_SBDROPERR (1<<6) +#define GT_FIFO_BLOBDROPERR (1<<5) +#define GT_FIFO_SB_READ_ABORTERR (1<<4) +#define GT_FIFO_DROPERR (1<<3) #define GT_FIFO_OVFERR (1<<2) #define GT_FIFO_IAWRERR (1<<1) #define GT_FIFO_IARDERR (1<<0) -#define GT_FIFO_FREE_ENTRIES 0x120008 +#define GTFIFOCTL 0x120008 +#define GT_FIFO_FREE_ENTRIES_MASK 0x7f #define GT_FIFO_NUM_RESERVED_ENTRIES 20 #define HSW_IDICR 0x9008 @@ -4890,6 +4875,7 @@ #define GEN6_RC_CTL_RC6_ENABLE (1<<18) #define GEN6_RC_CTL_RC1e_ENABLE (1<<20) #define GEN6_RC_CTL_RC7_ENABLE (1<<22) +#define VLV_RC_CTL_CTX_RST_PARALLEL (1<<24) #define GEN7_RC_CTL_TO_MODE (1<<28) #define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) #define GEN6_RC_CTL_HW_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 98790c7cccb1..8150fdc08d49 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -192,7 +192,6 @@ static void i915_restore_vga(struct drm_device *dev) static void i915_save_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long flags; /* Display arbitration control */ if (INTEL_INFO(dev)->gen <= 4) @@ -203,46 +202,27 @@ static void i915_save_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_save_display_reg(dev); - spin_lock_irqsave(&dev_priv->backlight.lock, flags); - /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); - dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); - dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); - dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); } else if (IS_VALLEYVIEW(dev)) { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->regfile.saveBLC_PWM_CTL = - I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(VLV_BLC_HIST_CTL(PIPE_A)); - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); - dev_priv->regfile.saveBLC_PWM_CTL_B = - I915_READ(VLV_BLC_PWM_CTL(PIPE_B)); dev_priv->regfile.saveBLC_HIST_CTL_B = I915_READ(VLV_BLC_HIST_CTL(PIPE_B)); - dev_priv->regfile.saveBLC_PWM_CTL2_B = - I915_READ(VLV_BLC_PWM_CTL2(PIPE_B)); } else { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); if (IS_MOBILE(dev) && !IS_I830(dev)) dev_priv->regfile.saveLVDS = I915_READ(LVDS); } - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); - if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); @@ -257,7 +237,7 @@ static void i915_save_display(struct drm_device *dev) } /* Only regfile.save FBC state on the platform that supports FBC */ - if (I915_HAS_FBC(dev)) { + if (HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); } else if (IS_GM45(dev)) { @@ -278,7 +258,6 @@ static void i915_restore_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 mask = 0xffffffff; - unsigned long flags; /* Display arbitration */ if (INTEL_INFO(dev)->gen <= 4) @@ -287,12 +266,6 @@ static void i915_restore_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_restore_display_reg(dev); - spin_lock_irqsave(&dev_priv->backlight.lock, flags); - - /* LVDS state */ - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - if (drm_core_check_feature(dev, DRIVER_MODESET)) mask = ~LVDS_PORT_EN; @@ -305,13 +278,6 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); - I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; - * otherwise we get blank eDP screen after S3 on some machines - */ - I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2); - I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL); I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); @@ -319,21 +285,12 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(RSTDBYCTL, dev_priv->regfile.saveMCHBAR_RENDER_STANDBY); } else if (IS_VALLEYVIEW(dev)) { - I915_WRITE(VLV_BLC_PWM_CTL(PIPE_A), - dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(VLV_BLC_HIST_CTL(PIPE_A), dev_priv->regfile.saveBLC_HIST_CTL); - I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_A), - dev_priv->regfile.saveBLC_PWM_CTL2); - I915_WRITE(VLV_BLC_PWM_CTL(PIPE_B), - dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(VLV_BLC_HIST_CTL(PIPE_B), dev_priv->regfile.saveBLC_HIST_CTL); - I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_B), - dev_priv->regfile.saveBLC_PWM_CTL2); } else { I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS); - I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL); I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL); I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); @@ -341,11 +298,9 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); } - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); - /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); - if (I915_HAS_FBC(dev)) { + if (HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); } else if (IS_GM45(dev)) { diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index cef38fd320a7..33bcae314bf8 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 @@ -183,13 +191,13 @@ i915_l3_write(struct file *filp, struct kobject *kobj, int slice = (int)(uintptr_t)attr->private; int ret; + if (!HAS_HW_CONTEXTS(drm_dev)) + return -ENXIO; + ret = l3_access_valid(drm_dev, offset); if (ret) return ret; - if (dev_priv->hw_contexts_disabled) - return -ENXIO; - ret = i915_mutex_lock_interruptible(drm_dev); if (ret) return ret; @@ -259,7 +267,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, if (IS_VALLEYVIEW(dev_priv->dev)) { u32 freq; freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff); + ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff); } else { ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; } @@ -276,8 +284,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev, struct drm_i915_private *dev_priv = dev->dev_private; return snprintf(buf, PAGE_SIZE, "%d\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.rpe_delay)); + vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay)); } static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) @@ -291,7 +298,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) - ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay); + ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay); else ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -318,7 +325,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); hw_max = valleyview_rps_max_freq(dev_priv); hw_min = valleyview_rps_min_freq(dev_priv); @@ -342,15 +349,15 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, DRM_DEBUG("User requested overclocking to %d\n", val * GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.max_delay = val; + if (dev_priv->rps.cur_delay > val) { - if (IS_VALLEYVIEW(dev_priv->dev)) - valleyview_set_rps(dev_priv->dev, val); + if (IS_VALLEYVIEW(dev)) + valleyview_set_rps(dev, val); else - gen6_set_rps(dev_priv->dev, val); + gen6_set_rps(dev, val); } - dev_priv->rps.max_delay = val; - mutex_unlock(&dev_priv->rps.hw_lock); return count; @@ -367,7 +374,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) - ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay); + ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay); else ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); @@ -394,7 +401,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev)) { - val = vlv_freq_opcode(dev_priv->mem_freq, val); + val = vlv_freq_opcode(dev_priv, val); hw_max = valleyview_rps_max_freq(dev_priv); hw_min = valleyview_rps_min_freq(dev_priv); @@ -411,15 +418,15 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, return -EINVAL; } + dev_priv->rps.min_delay = val; + if (dev_priv->rps.cur_delay < val) { if (IS_VALLEYVIEW(dev)) valleyview_set_rps(dev, val); else - gen6_set_rps(dev_priv->dev, val); + gen6_set_rps(dev, val); } - dev_priv->rps.min_delay = val; - mutex_unlock(&dev_priv->rps.hw_lock); return count; @@ -449,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/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 967da4772c44..caa18e855815 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -270,6 +270,18 @@ void i915_save_display_reg(struct drm_device *dev) } /* FIXME: regfile.save TV & SDVO state */ + /* Backlight */ + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); + dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); + dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); + } else { + dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (INTEL_INFO(dev)->gen >= 4) + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + } + return; } @@ -280,6 +292,21 @@ void i915_restore_display_reg(struct drm_device *dev) int dpll_b_reg, fpb0_reg, fpb1_reg; int i; + /* Backlight */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); + I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); + /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; + * otherwise we get blank eDP screen after S3 on some machines + */ + I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL); + } else { + if (INTEL_INFO(dev)->gen >= 4) + I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL); + } + /* Display port ratios (must be done before clock is set) */ if (SUPPORTS_INTEGRATED_DP(dev)) { I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index e4fba39631a5..f22041973f3a 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -281,6 +281,34 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, } } +static void +parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + const struct bdb_lfp_backlight_data *backlight_data; + const struct bdb_lfp_backlight_data_entry *entry; + + backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); + if (!backlight_data) + return; + + if (backlight_data->entry_size != sizeof(backlight_data->data[0])) { + DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n", + backlight_data->entry_size); + return; + } + + entry = &backlight_data->data[panel_type]; + + dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; + dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; + DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " + "active %s, min brightness %u, level %u\n", + dev_priv->vbt.backlight.pwm_freq_hz, + dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", + entry->min_brightness, + backlight_data->level[panel_type]); +} + /* Try to find sdvo panel data */ static void parse_sdvo_panel_data(struct drm_i915_private *dev_priv, @@ -327,12 +355,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 +824,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 = @@ -894,6 +922,7 @@ intel_parse_bios(struct drm_device *dev) parse_general_features(dev_priv, bdb); parse_general_definitions(dev_priv, bdb); parse_lfp_panel_data(dev_priv, bdb); + parse_lfp_backlight(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); parse_sdvo_device_mapping(dev_priv, bdb); parse_device_mapping(dev_priv, bdb); diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index f580a2b0ddd3..282de5e9f39d 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,33 @@ 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 bdb_lfp_backlight_data_entry { + u8 type:2; + u8 active_low_pwm:1; + u8 obsolete1:5; + u16 pwm_freq_hz; + u8 min_brightness; + u8 obsolete2; + u8 obsolete3; +} __packed; + +struct bdb_lfp_backlight_data { + u8 entry_size; + struct bdb_lfp_backlight_data_entry data[16]; + u8 level[16]; +} __packed; struct aimdb_header { char signature[16]; @@ -379,12 +395,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 +411,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 +432,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 +478,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 +503,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 +521,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 +749,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_crt.c b/drivers/gpu/drm/i915/intel_crt.c index b5b1b9b23adf..e2e39e65f109 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -222,8 +222,9 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) intel_modeset_check_state(connector->dev); } -static int intel_crt_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_crt_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b69dc3e66c16..74749c6f897e 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,25 +696,25 @@ 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; - /* TODO: reuse PLLs when possible (compare values) */ - intel_ddi_put_crtc_pll(crtc); if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { @@ -736,66 +736,145 @@ 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; - if (plls->wrpll1_refcount == 0) { + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p); + + if (val == I915_READ(WRPLL_CTL1)) { + DRM_DEBUG_KMS("Reusing WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL1; + } else if (val == I915_READ(WRPLL_CTL2)) { + DRM_DEBUG_KMS("Reusing WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + reg = WRPLL_CTL2; + } else if (plls->wrpll1_refcount == 0) { DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", pipe_name(pipe)); - plls->wrpll1_refcount++; reg = WRPLL_CTL1; - intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; } else if (plls->wrpll2_refcount == 0) { DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n", pipe_name(pipe)); - plls->wrpll2_refcount++; reg = WRPLL_CTL2; - intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; } else { DRM_ERROR("No WRPLLs available!\n"); return false; } - WARN(I915_READ(reg) & WRPLL_PLL_ENABLE, - "WRPLL already enabled\n"); + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, p, n2, r2); - intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); - - val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | - WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | - WRPLL_DIVIDER_POST(p); + if (reg == WRPLL_CTL1) { + plls->wrpll1_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; + } else { + plls->wrpll2_refcount++; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; + } } else if (type == INTEL_OUTPUT_ANALOG) { if (plls->spll_refcount == 0) { 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; @@ -1121,9 +1200,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); @@ -1166,7 +1243,7 @@ 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 2bde35d34eb9..e77d4b8856a7 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); } @@ -748,10 +754,10 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, return intel_crtc->config.cpu_transcoder; } -static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) +static void g4x_wait_for_vblank(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 frame, frame_reg = PIPEFRAME(pipe); + u32 frame, frame_reg = PIPE_FRMCOUNT_GM45(pipe); frame = I915_READ(frame_reg); @@ -772,8 +778,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private; int pipestat_reg = PIPESTAT(pipe); - if (INTEL_INFO(dev)->gen >= 5) { - ironlake_wait_for_vblank(dev, pipe); + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + g4x_wait_for_vblank(dev, pipe); return; } @@ -1205,15 +1211,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, } } -static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) +static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) { u32 val; bool enabled; - if (HAS_PCH_LPT(dev_priv->dev)) { - DRM_DEBUG_DRIVER("LPT does not has PCH refclk, skipping check\n"); - return; - } + WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev))); val = I915_READ(PCH_DREF_CONTROL); enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | @@ -1361,6 +1364,24 @@ static void intel_init_dpio(struct drm_device *dev) if (!IS_VALLEYVIEW(dev)) return; + DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; +} + +static void intel_reset_dpio(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_VALLEYVIEW(dev)) + return; + + /* + * Enable the CRI clock source so we can get at the display and the + * reference clock for VGA hotplug / manual detection. + */ + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_REFA_CLK_ENABLE_VLV | + DPLL_INTEGRATED_CRI_CLK_VLV); + /* * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - * 6. De-assert cmn_reset/side_reset. Same as VLV X0. @@ -1487,25 +1508,35 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) /* Make sure the pipe isn't still relying on us */ assert_pipe_disabled(dev_priv, pipe); - /* Leave integrated clock source enabled */ + /* + * Leave integrated clock source and reference clock enabled for pipe B. + * The latter is needed for VGA hotplug / manual detection. + */ if (pipe == PIPE_B) - val = DPLL_INTEGRATED_CRI_CLK_VLV; + val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), val); POSTING_READ(DPLL(pipe)); } -void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) +void vlv_wait_port_ready(struct drm_i915_private *dev_priv, + struct intel_digital_port *dport) { u32 port_mask; - if (!port) + switch (dport->port) { + case PORT_B: port_mask = DPLL_PORTB_READY_MASK; - else + break; + case PORT_C: port_mask = DPLL_PORTC_READY_MASK; + break; + default: + BUG(); + } if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000)) WARN(1, "timed out waiting for port %c ready: 0x%08x\n", - 'B' + port, I915_READ(DPLL(0))); + port_name(dport->port), I915_READ(DPLL(0))); } /** @@ -2233,7 +2264,12 @@ void intel_display_handle_reset(struct drm_device *dev) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); mutex_lock(&crtc->mutex); - if (intel_crtc->active) + /* + * FIXME: Once we have proper support for primary planes (and + * disabling them without disabling the entire crtc) allow again + * a NULL crtc->fb. + */ + if (intel_crtc->active && crtc->fb) dev_priv->display.update_plane(crtc, crtc->fb, crtc->x, crtc->y); mutex_unlock(&crtc->mutex); @@ -2350,6 +2386,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0); I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0); } + intel_crtc->config.pipe_src_w = adjusted_mode->crtc_hdisplay; + intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay; } ret = dev_priv->display.update_plane(crtc, fb, x, y); @@ -3399,9 +3437,8 @@ void hsw_enable_ips(struct intel_crtc *crtc) mutex_unlock(&dev_priv->rps.hw_lock); /* Quoting Art Runyan: "its not safe to expect any particular * value in IPS_CTL bit 31 after enabling IPS through the - * mailbox." Therefore we need to defer waiting on the state - * change. - * TODO: need to fix this for state checker + * mailbox." Moreover, the mailbox may return a bogus state, + * so we need to just enable it and continue on. */ } else { I915_WRITE(IPS_CTL, IPS_ENABLE); @@ -3428,9 +3465,10 @@ void hsw_disable_ips(struct intel_crtc *crtc) mutex_lock(&dev_priv->rps.hw_lock); WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0)); mutex_unlock(&dev_priv->rps.hw_lock); - } else + } else { I915_WRITE(IPS_CTL, 0); - POSTING_READ(IPS_CTL); + POSTING_READ(IPS_CTL); + } /* We need to wait for a vblank before we can disable the plane. */ intel_wait_for_vblank(dev, crtc->pipe); @@ -3465,7 +3503,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) /* Workaround : Do not read or write the pipe palette/gamma data while * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. */ - if (intel_crtc->config.ips_enabled && + if (IS_HASWELL(dev) && intel_crtc->config.ips_enabled && ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) == GAMMA_MODE_MODE_SPLIT)) { hsw_disable_ips(intel_crtc); @@ -3910,6 +3948,174 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } +int valleyview_get_vco(struct drm_i915_private *dev_priv) +{ + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + + /* Obtain SKU information */ + mutex_lock(&dev_priv->dpio_lock); + hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + mutex_unlock(&dev_priv->dpio_lock); + + return vco_freq[hpll_freq]; +} + +/* Adjust CDclk dividers to allow high res or save power if possible */ +static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val, cmd; + + if (cdclk >= 320) /* jump to highest voltage for 400MHz too */ + cmd = 2; + else if (cdclk == 266) + cmd = 1; + else + cmd = 0; + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + val &= ~DSPFREQGUAR_MASK; + val |= (cmd << DSPFREQGUAR_SHIFT); + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val); + if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & + DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), + 50)) { + DRM_ERROR("timed out waiting for CDclk change\n"); + } + mutex_unlock(&dev_priv->rps.hw_lock); + + if (cdclk == 400) { + u32 divider, vco; + + vco = valleyview_get_vco(dev_priv); + divider = ((vco << 1) / cdclk) - 1; + + mutex_lock(&dev_priv->dpio_lock); + /* adjust cdclk divider */ + val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); + val &= ~0xf; + val |= divider; + vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val); + mutex_unlock(&dev_priv->dpio_lock); + } + + mutex_lock(&dev_priv->dpio_lock); + /* adjust self-refresh exit latency value */ + val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC); + val &= ~0x7f; + + /* + * For high bandwidth configs, we set a higher latency in the bunit + * so that the core display fetch happens in time to avoid underruns. + */ + if (cdclk == 400) + val |= 4500 / 250; /* 4.5 usec */ + else + val |= 3000 / 250; /* 3.0 usec */ + vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val); + mutex_unlock(&dev_priv->dpio_lock); + + /* Since we changed the CDclk, we need to update the GMBUSFREQ too */ + intel_i2c_reset(dev); +} + +static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) +{ + int cur_cdclk, vco; + int divider; + + vco = valleyview_get_vco(dev_priv); + + mutex_lock(&dev_priv->dpio_lock); + divider = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); + mutex_unlock(&dev_priv->dpio_lock); + + divider &= 0xf; + + cur_cdclk = (vco << 1) / (divider + 1); + + return cur_cdclk; +} + +static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixclk) +{ + int cur_cdclk; + + cur_cdclk = valleyview_cur_cdclk(dev_priv); + + /* + * Really only a few cases to deal with, as only 4 CDclks are supported: + * 200MHz + * 267MHz + * 320MHz + * 400MHz + * So we check to see whether we're above 90% of the lower bin and + * adjust if needed. + */ + if (max_pixclk > 288000) { + return 400; + } else if (max_pixclk > 240000) { + return 320; + } else + return 266; + /* Looks like the 200MHz CDclk freq doesn't work on some configs */ +} + +static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv, + unsigned modeset_pipes, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc; + int max_pixclk = 0; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + if (modeset_pipes & (1 << intel_crtc->pipe)) + max_pixclk = max(max_pixclk, + pipe_config->adjusted_mode.crtc_clock); + else if (intel_crtc->base.enabled) + max_pixclk = max(max_pixclk, + intel_crtc->config.adjusted_mode.crtc_clock); + } + + return max_pixclk; +} + +static void valleyview_modeset_global_pipes(struct drm_device *dev, + unsigned *prepare_pipes, + unsigned modeset_pipes, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes, + pipe_config); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + + if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk) + return; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) + if (intel_crtc->base.enabled) + *prepare_pipes |= (1 << intel_crtc->pipe); +} + +static void valleyview_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); + + if (req_cdclk != cur_cdclk) + valleyview_set_cdclk(dev, req_cdclk); +} + static void valleyview_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -4570,9 +4776,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 { @@ -4634,24 +4839,24 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe * PLLB opamp always calibrates to max value of 0x3f, force enable it * and set it to a reasonable value instead. */ - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1)); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; reg_val |= 0x00000030; - vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); reg_val &= 0x8cffffff; reg_val = 0x8c000000; - vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1)); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; - vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); reg_val &= 0x00ffffff; reg_val |= 0xb0000000; - vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); } static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, @@ -4720,15 +4925,15 @@ static void vlv_update_pll(struct intel_crtc *crtc) vlv_pllb_recal_opamp(dev_priv, pipe); /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(dev_priv, pipe, DPIO_IREF_BCAST, 0x0100000f); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); /* Disable target IRef on PLL */ - reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF_CTL(pipe)); + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); reg_val &= 0x00ffffff; - vlv_dpio_write(dev_priv, pipe, DPIO_IREF_CTL(pipe), reg_val); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); /* Disable fast lock */ - vlv_dpio_write(dev_priv, pipe, DPIO_FASTCLK_DISABLE, 0x610); + vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); /* Set idtafcrecal before PLL is enabled */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); @@ -4742,50 +4947,54 @@ static void vlv_update_pll(struct intel_crtc *crtc) * Note: don't use the DAC post divider as it seems unstable. */ mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); mdiv |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ if (crtc->config.port_clock == 162000 || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), 0x009f0003); else - vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), 0x00d0000f); if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) { /* Use SSC source */ if (!pipe) - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df40000); else - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df70000); } else { /* HDMI or VGA */ /* Use bend source */ if (!pipe) - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df70000); else - vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), 0x0df40000); } - coreclk = vlv_dpio_read(dev_priv, pipe, DPIO_CORE_CLK(pipe)); + coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); coreclk = (coreclk & 0x0000ff00) | 0x01c00000; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) coreclk |= 0x01000000; - vlv_dpio_write(dev_priv, pipe, DPIO_CORE_CLK(pipe), coreclk); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); - vlv_dpio_write(dev_priv, pipe, DPIO_PLL_CML(pipe), 0x87871000); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); - /* Enable DPIO clock input */ + /* + * Enable DPIO clock input. We should never disable the reference + * clock for pipe B, since VGA hotplug / manual detection depends + * on it. + */ dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; /* We should never disable this, set it here for state tracking */ @@ -5230,6 +5439,9 @@ static void i9xx_get_pfit_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev))) + return; + tmp = I915_READ(PFIT_CONTROL); if (!(tmp & PFIT_ENABLE)) return; @@ -5261,7 +5473,7 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, int refclk = 100000; mutex_lock(&dev_priv->dpio_lock); - mdiv = vlv_dpio_read(dev_priv, pipe, DPIO_DIV(pipe)); + mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); mutex_unlock(&dev_priv->dpio_lock); clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; @@ -5718,9 +5930,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; @@ -5982,7 +6194,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) @@ -6323,7 +6535,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, @@ -6402,7 +6614,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) /* Make sure we're not on PC8 state before disabling PC8, otherwise * we'll hang the machine! */ - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); if (val & LCPLL_POWER_DOWN_ALLOW) { val &= ~LCPLL_POWER_DOWN_ALLOW; @@ -6436,7 +6648,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) DRM_ERROR("Switching back to LCPLL failed\n"); } - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } void hsw_enable_pc8_work(struct work_struct *__work) @@ -6447,6 +6659,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; @@ -6463,6 +6677,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) @@ -6492,12 +6708,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); @@ -6704,8 +6924,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); @@ -6796,8 +7017,9 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, if (intel_display_power_enabled(dev, pfit_domain)) ironlake_get_pfit_config(crtc, pipe_config); - pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && - (I915_READ(IPS_CTL) & IPS_ENABLE); + if (IS_HASWELL(dev)) + pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + (I915_READ(IPS_CTL) & IPS_ENABLE); pipe_config->pixel_multiplier = 1; @@ -7689,7 +7911,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)) @@ -7752,12 +7974,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 = IS_I830(dev) ? 0 : 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; @@ -9122,7 +9349,9 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pch_pfit.size); } - PIPE_CONF_CHECK_I(ips_enabled); + /* BDW+ don't expose a synchronous way to read the state */ + if (IS_HASWELL(dev)) + PIPE_CONF_CHECK_I(ips_enabled); PIPE_CONF_CHECK_I(double_wide); @@ -9402,6 +9631,21 @@ static int __intel_set_mode(struct drm_crtc *crtc, "[modeset]"); } + /* + * See if the config requires any additional preparation, e.g. + * to adjust global state with pipes off. We need to do this + * here so we can get the modeset_pipe updated config for the new + * mode set on this crtc. For other crtcs we need to use the + * adjusted_mode bits in the crtc directly. + */ + if (IS_VALLEYVIEW(dev)) { + valleyview_modeset_global_pipes(dev, &prepare_pipes, + modeset_pipes, pipe_config); + + /* may have added more to prepare_pipes than we should */ + prepare_pipes &= ~disable_pipes; + } + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); @@ -9694,17 +9938,21 @@ intel_modeset_stage_output_state(struct drm_device *dev, /* Check for any encoders that needs to be disabled. */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + int num_connectors = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { if (connector->new_encoder == encoder) { WARN_ON(!connector->new_encoder->new_crtc); - - goto next_encoder; + num_connectors++; } } - encoder->new_crtc = NULL; -next_encoder: + + if (num_connectors == 0) + encoder->new_crtc = NULL; + else if (num_connectors > 1) + return -EINVAL; + /* Only now check for crtc changes so we don't miss encoders * that will be disabled. */ if (&encoder->new_crtc->base != encoder->base.crtc) { @@ -9775,6 +10023,16 @@ static int intel_crtc_set_config(struct drm_mode_set *set) ret = intel_pipe_set_base(set->crtc, set->x, set->y, set->fb); + /* + * In the fastboot case this may be our only check of the + * state after boot. It would be better to only do it on + * the first update, but we don't have a nice way of doing that + * (and really, set_config isn't used much for high freq page + * flipping, so increasing its cost here shouldn't be a big + * deal). + */ + if (i915_fastboot && ret == 0) + intel_modeset_check_state(set->crtc->dev); } if (ret) { @@ -9835,7 +10093,7 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { /* PCH refclock must be enabled first */ - assert_pch_refclk_enabled(dev_priv); + ibx_assert_pch_refclk_enabled(dev_priv); I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); @@ -9903,8 +10161,6 @@ static void intel_shared_dpll_init(struct drm_device *dev) dev_priv->num_shared_dpll = 0; BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); - DRM_DEBUG_KMS("%i shared PLLs initialized\n", - dev_priv->num_shared_dpll); } static void intel_crtc_init(struct drm_device *dev, int pipe) @@ -9926,10 +10182,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 (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; } @@ -10018,6 +10277,28 @@ static bool has_edp_a(struct drm_device *dev) return true; } +const char *intel_output_name(int output) +{ + static const char *names[] = { + [INTEL_OUTPUT_UNUSED] = "Unused", + [INTEL_OUTPUT_ANALOG] = "Analog", + [INTEL_OUTPUT_DVO] = "DVO", + [INTEL_OUTPUT_SDVO] = "SDVO", + [INTEL_OUTPUT_LVDS] = "LVDS", + [INTEL_OUTPUT_TVOUT] = "TV", + [INTEL_OUTPUT_HDMI] = "HDMI", + [INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort", + [INTEL_OUTPUT_EDP] = "eDP", + [INTEL_OUTPUT_DSI] = "DSI", + [INTEL_OUTPUT_UNKNOWN] = "Unknown", + }; + + if (output < 0 || output >= ARRAY_SIZE(names) || !names[output]) + return "Invalid"; + + return names[output]; +} + static void intel_setup_outputs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -10412,8 +10693,11 @@ static void intel_init_display(struct drm_device *dev) } } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; - } else if (IS_VALLEYVIEW(dev)) + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.modeset_global_resources = + valleyview_modeset_global_resources; dev_priv->display.write_eld = ironlake_write_eld; + } /* Default just returns -ENODEV to indicate unsupported */ dev_priv->display.queue_flip = intel_default_queue_flip; @@ -10440,6 +10724,8 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.queue_flip = intel_gen7_queue_flip; break; } + + intel_panel_init_backlight_funcs(dev); } /* @@ -10476,17 +10762,6 @@ static void quirk_invert_brightness(struct drm_device *dev) DRM_INFO("applying inverted panel brightness quirk\n"); } -/* - * Some machines (Dell XPS13) suffer broken backlight controls if - * BLM_PCH_PWM_ENABLE is set. - */ -static void quirk_no_pcm_pwm_enable(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE; - DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n"); -} - struct intel_quirk { int device; int subsystem_vendor; @@ -10555,11 +10830,6 @@ static struct intel_quirk intel_quirks[] = { /* Acer Aspire 4736Z */ { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, - - /* Dell XPS13 HD Sandy Bridge */ - { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable }, - /* Dell XPS13 HD and XPS13 FHD Ivy Bridge */ - { 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable }, }; static void intel_init_quirks(struct drm_device *dev) @@ -10603,18 +10873,11 @@ 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); + intel_reset_dpio(dev); mutex_lock(&dev->struct_mutex); intel_enable_gt_powersave(dev); @@ -10676,6 +10939,9 @@ void intel_modeset_init(struct drm_device *dev) } } + intel_init_dpio(dev); + intel_reset_dpio(dev); + intel_cpu_pll_init(dev); intel_shared_dpll_init(dev); @@ -10879,7 +11145,7 @@ void i915_redisable_vga(struct drm_device *dev) * level, just check if the power well is enabled instead of trying to * follow the "don't touch the power well if we don't need it" policy * the rest of the driver uses. */ - if (HAS_POWER_WELL(dev) && + if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0) return; @@ -11023,7 +11289,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (IS_HASWELL(dev)) + if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); if (force_restore) { @@ -11101,12 +11367,11 @@ void intel_modeset_cleanup(struct drm_device *dev) /* flush any delayed tasks or pending work */ flush_scheduled_work(); - /* destroy backlight, if any, before the connectors */ - intel_panel_destroy_backlight(dev); - - /* destroy the sysfs files before encoders/connectors */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + /* destroy the backlight and sysfs files before encoders/connectors */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + intel_panel_destroy_backlight(connector); drm_sysfs_connector_remove(connector); + } drm_mode_config_cleanup(dev); @@ -11161,6 +11426,7 @@ struct intel_display_error_state { } cursor[I915_MAX_PIPES]; struct intel_pipe_error_state { + bool power_domain_on; u32 source; } pipe[I915_MAX_PIPES]; @@ -11175,6 +11441,7 @@ struct intel_display_error_state { } plane[I915_MAX_PIPES]; struct intel_transcoder_error_state { + bool power_domain_on; enum transcoder cpu_transcoder; u32 conf; @@ -11208,11 +11475,13 @@ intel_display_capture_error_state(struct drm_device *dev) if (error == NULL) return NULL; - if (HAS_POWER_WELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); for_each_pipe(i) { - if (!intel_display_power_enabled(dev, POWER_DOMAIN_PIPE(i))) + error->pipe[i].power_domain_on = + intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i)); + if (!error->pipe[i].power_domain_on) continue; if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { @@ -11248,8 +11517,10 @@ intel_display_capture_error_state(struct drm_device *dev) for (i = 0; i < error->num_transcoders; i++) { enum transcoder cpu_transcoder = transcoders[i]; - if (!intel_display_power_enabled(dev, - POWER_DOMAIN_TRANSCODER(cpu_transcoder))) + error->transcoder[i].power_domain_on = + intel_display_power_enabled_sw(dev, + POWER_DOMAIN_TRANSCODER(cpu_transcoder)); + if (!error->transcoder[i].power_domain_on) continue; error->transcoder[i].cpu_transcoder = cpu_transcoder; @@ -11279,11 +11550,13 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, return; err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); - if (HAS_POWER_WELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) err_printf(m, "PWR_WELL_CTL2: %08x\n", error->power_well_driver); for_each_pipe(i) { err_printf(m, "Pipe [%d]:\n", i); + err_printf(m, " Power: %s\n", + error->pipe[i].power_domain_on ? "on" : "off"); err_printf(m, " SRC: %08x\n", error->pipe[i].source); err_printf(m, "Plane [%d]:\n", i); @@ -11309,6 +11582,8 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, for (i = 0; i < error->num_transcoders; i++) { err_printf(m, "CPU transcoder: %c\n", transcoder_name(error->transcoder[i].cpu_transcoder)); + err_printf(m, " Power: %s\n", + error->transcoder[i].power_domain_on ? "on" : "off"); err_printf(m, " CONF: %08x\n", error->transcoder[i].conf); err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal); err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 30c627c7b7ba..9b40113f4fa1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -142,7 +142,7 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes) return (max_link_clock * max_lanes * 8) / 10; } -static int +static enum drm_mode_status intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { @@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, int i, ret, recv_bytes; uint32_t status; int try, precharge, clock = 0; - bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev); + bool has_aux_irq = true; uint32_t timeout; /* dp aux is extremely sensitive to irq latency, hence request the @@ -1037,6 +1037,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) @@ -1092,6 +1094,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)) @@ -1140,7 +1144,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); } } @@ -1233,20 +1241,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); } @@ -1772,7 +1776,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); @@ -1845,23 +1848,23 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) 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); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; struct edp_power_seq power_seq; u32 val; mutex_lock(&dev_priv->dpio_lock); - val = vlv_dpio_read(dev_priv, pipe, DPIO_DATA_LANE_A(port)); + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - vlv_dpio_write(dev_priv, pipe, DPIO_DATA_CHANNEL(port), val); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF0(port), 0x00760018); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF8(port), 0x00400888); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); mutex_unlock(&dev_priv->dpio_lock); @@ -1872,7 +1875,7 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) intel_enable_dp(encoder); - vlv_wait_port_ready(dev_priv, port); + vlv_wait_port_ready(dev_priv, dport); } static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) @@ -1882,24 +1885,24 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; /* Program Tx lane resets to default */ mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) | DPIO_PCS_CLK_SOFT_RESET); /* Fix up inter-pair skew failure */ - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER1(port), 0x00750f00); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_CTL(port), 0x00001500); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_LANE(port), 0x40400000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000); mutex_unlock(&dev_priv->dpio_lock); } @@ -1941,18 +1944,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 @@ -2050,7 +2041,7 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) unsigned long demph_reg_value, preemph_reg_value, uniqtranscale_reg_value; uint8_t train_set = intel_dp->train_set[0]; - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { @@ -2127,14 +2118,14 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) } mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL4(port), demph_reg_value); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL2(port), + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), uniqtranscale_reg_value); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL3(port), 0x0C782040); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER0(port), 0x00030000); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port), preemph_reg_value); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0x80000000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x80000000); mutex_unlock(&dev_priv->dpio_lock); return 0; @@ -3082,9 +3073,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)); @@ -3096,7 +3090,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); @@ -3112,7 +3106,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 79f91f26e288..8754db9e3d52 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -65,8 +65,8 @@ #define wait_for_atomic_us(COND, US) _wait_for((COND), \ DIV_ROUND_UP((US), 1000), 0) -#define KHz(x) (1000*x) -#define MHz(x) KHz(1000*x) +#define KHz(x) (1000 * (x)) +#define MHz(x) KHz(1000 * (x)) /* * Display related stuff @@ -155,7 +155,19 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; + struct drm_display_mode *downclock_mode; int fitting_mode; + + /* backlight */ + struct { + bool present; + u32 level; + u32 max; + bool enabled; + bool combination_mode; /* gen 2/4 only */ + bool active_low_pwm; + struct backlight_device *device; + } backlight; }; struct intel_connector { @@ -443,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); }; @@ -490,9 +502,9 @@ vlv_dport_to_channel(struct intel_digital_port *dport) { switch (dport->port) { case PORT_B: - return 0; + return DPIO_CH0; case PORT_C: - return 1; + return DPIO_CH1; default: BUG(); } @@ -601,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); @@ -612,6 +625,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, /* intel_display.c */ +const char *intel_output_name(int output); int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_fb_busy(struct drm_i915_gem_object *obj, @@ -638,7 +652,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, void intel_wait_for_vblank(struct drm_device *dev, int pipe); void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); -void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port); +void vlv_wait_port_ready(struct drm_i915_private *dev_priv, + struct intel_digital_port *dport); bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, struct intel_load_detect_pipe *old); @@ -690,11 +705,10 @@ 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); - +int valleyview_get_vco(struct drm_i915_private *dev_priv); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); @@ -808,9 +822,13 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, int intel_panel_setup_backlight(struct drm_connector *connector); void intel_panel_enable_backlight(struct intel_connector *connector); void intel_panel_disable_backlight(struct intel_connector *connector); -void intel_panel_destroy_backlight(struct drm_device *dev); +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); @@ -830,6 +848,8 @@ int intel_power_domains_init(struct drm_device *dev); void intel_power_domains_remove(struct drm_device *dev); bool intel_display_power_enabled(struct drm_device *dev, enum intel_display_power_domain domain); +bool intel_display_power_enabled_sw(struct drm_device *dev, + enum intel_display_power_domain domain); void intel_display_power_get(struct drm_device *dev, enum intel_display_power_domain domain); void intel_display_power_put(struct drm_device *dev, @@ -844,6 +864,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 d257b093ca68..fabbf0d895cf 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) @@ -251,8 +272,9 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, /* XXX: read flags, set to adjusted_mode */ } -static int intel_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; @@ -352,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? */ @@ -373,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 | @@ -425,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 */ @@ -442,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 c7765f33d524..b4a27cec882f 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 44279b2ade88..ba79ec19da3b 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_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 3c7736546856..eeff998e52ef 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -234,8 +234,9 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) intel_modeset_check_state(connector->dev); } -static int intel_dvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_dvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 895fcb4fbd94..39eac9937a4a 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -57,18 +57,14 @@ static struct fb_ops intelfb_ops = { .fb_debug_leave = drm_fb_helper_debug_leave, }; -static int intelfb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) +static int intelfb_alloc(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); struct drm_device *dev = helper->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct fb_info *info; - struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; - struct device *device = &dev->pdev->dev; int size, ret; /* we don't do packed 24bpp */ @@ -94,8 +90,6 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out; } - mutex_lock(&dev->struct_mutex); - /* Flush everything out, we'll be doing GTT only from now on */ ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { @@ -103,7 +97,50 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out_unref; } - info = framebuffer_alloc(0, device); + ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); + if (ret) + goto out_unpin; + + return 0; + +out_unpin: + i915_gem_object_unpin(obj); +out_unref: + drm_gem_object_unreference(&obj->base); +out: + return ret; +} + +static int intelfb_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct intel_fbdev *ifbdev = + container_of(helper, struct intel_fbdev, helper); + struct intel_framebuffer *intel_fb = &ifbdev->ifb; + struct drm_device *dev = helper->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_i915_gem_object *obj; + int size, ret; + + mutex_lock(&dev->struct_mutex); + + if (!intel_fb->obj) { + DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); + ret = intelfb_alloc(helper, sizes); + if (ret) + goto out_unlock; + } else { + DRM_DEBUG_KMS("re-using BIOS fb\n"); + sizes->fb_width = intel_fb->base.width; + sizes->fb_height = intel_fb->base.height; + } + + obj = intel_fb->obj; + size = obj->base.size; + + info = framebuffer_alloc(0, &dev->pdev->dev); if (!info) { ret = -ENOMEM; goto out_unpin; @@ -111,10 +148,6 @@ static int intelfb_create(struct drm_fb_helper *helper, info->par = helper; - ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); - if (ret) - goto out_unpin; - fb = &ifbdev->ifb.base; ifbdev->helper.fb = fb; @@ -170,17 +203,15 @@ static int intelfb_create(struct drm_fb_helper *helper, fb->width, fb->height, i915_gem_obj_ggtt_offset(obj), obj); - mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; out_unpin: i915_gem_object_unpin(obj); -out_unref: drm_gem_object_unreference(&obj->base); +out_unlock: mutex_unlock(&dev->struct_mutex); -out: return ret; } @@ -297,8 +328,6 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) fb_set_suspend(info, state); } -MODULE_LICENSE("GPL and additional rights"); - void intel_fbdev_output_poll_changed(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 03f9ca70530c..6db0d9d17f47 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); @@ -853,8 +853,9 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi) return 225000; } -static int intel_hdmi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector))) return MODE_CLOCK_HIGH; @@ -1081,7 +1082,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; u32 val; @@ -1090,41 +1091,33 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) /* Enable clock channels for this port */ mutex_lock(&dev_priv->dpio_lock); - val = vlv_dpio_read(dev_priv, pipe, DPIO_DATA_LANE_A(port)); + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - vlv_dpio_write(dev_priv, pipe, DPIO_DATA_CHANNEL(port), val); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); /* HDMI 1.0V-2dB */ - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL4(port), - 0x2b245f5f); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL2(port), - 0x5578b83a); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL3(port), - 0x0c782040); - vlv_dpio_write(dev_priv, pipe, DPIO_TX3_SWING_CTL4(port), - 0x2b247878); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER0(port), 0x00030000); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port), - 0x00002000); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), - DPIO_TX_OCALINIT_EN); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040); + vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); /* Program lane clock */ - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF0(port), - 0x00760018); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF8(port), - 0x00400888); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); mutex_unlock(&dev_priv->dpio_lock); intel_enable_hdmi(encoder); - vlv_wait_port_ready(dev_priv, port); + vlv_wait_port_ready(dev_priv, dport); } static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) @@ -1134,7 +1127,7 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - int port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; if (!IS_VALLEYVIEW(dev)) @@ -1142,24 +1135,22 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) /* Program Tx lane resets to default */ mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) | DPIO_PCS_CLK_SOFT_RESET); /* Fix up inter-pair skew failure */ - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER1(port), 0x00750f00); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_CTL(port), 0x00001500); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_LANE(port), 0x40400000); - - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port), - 0x00002000); - vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), - DPIO_TX_OCALINIT_EN); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000); + + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); + vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); mutex_unlock(&dev_priv->dpio_lock); } @@ -1169,13 +1160,13 @@ static void vlv_hdmi_post_disable(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 port = vlv_dport_to_channel(dport); + enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; /* Reset lanes to avoid HDMI flicker (VLV w/a) */ mutex_lock(&dev_priv->dpio_lock); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), 0x00e00060); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); + vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); mutex_unlock(&dev_priv->dpio_lock); } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 2ca17b14b6c1..b1dc33f47899 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -82,20 +82,11 @@ static int get_disp_clk_div(struct drm_i915_private *dev_priv, static void gmbus_set_freq(struct drm_i915_private *dev_priv) { - int vco_freq[] = { 800, 1600, 2000, 2400 }; - int gmbus_freq = 0, cdclk_div, hpll_freq; + int vco, gmbus_freq = 0, cdclk_div; BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); - /* Skip setting the gmbus freq if BIOS has already programmed it */ - if (I915_READ(GMBUSFREQ_VLV) != 0xA0) - return; - - /* Obtain SKU information */ - mutex_lock(&dev_priv->dpio_lock); - hpll_freq = - vlv_cck_read(dev_priv, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK; - mutex_unlock(&dev_priv->dpio_lock); + vco = valleyview_get_vco(dev_priv); /* Get the CDCLK divide ratio */ cdclk_div = get_disp_clk_div(dev_priv, CDCLK); @@ -106,7 +97,7 @@ static void gmbus_set_freq(struct drm_i915_private *dev_priv) * in fact 1MHz is the correct frequency. */ if (cdclk_div) - gmbus_freq = (vco_freq[hpll_freq] << 1) / cdclk_div; + gmbus_freq = (vco << 1) / cdclk_div; if (WARN_ON(gmbus_freq == 0)) return; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index c3b4da7895ed..8bcb93a2a9f6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -256,8 +256,9 @@ static void intel_disable_lvds(struct intel_encoder *encoder) POSTING_READ(lvds_encoder->reg); } -static int intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_lvds_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; @@ -446,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; @@ -744,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. @@ -1072,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 6d69a9bad865..3da259e280ba 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) @@ -396,13 +396,10 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_encoder *encoder; struct drm_connector *connector; - struct intel_connector *intel_connector = NULL; - struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; + struct intel_connector *intel_connector; + struct intel_panel *panel; struct opregion_asle __iomem *asle = dev_priv->opregion.asle; - u32 ret = 0; - bool found = false; DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); @@ -414,38 +411,24 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) return ASLC_BACKLIGHT_FAILED; mutex_lock(&dev->mode_config.mutex); + /* - * Could match the OpRegion connector here instead, but we'd also need - * to verify the connector could handle a backlight call. + * Update backlight on all connectors that support backlight (usually + * only one). */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->crtc == crtc) { - found = true; - break; - } - - if (!found) { - ret = ASLC_BACKLIGHT_FAILED; - goto out; - } - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - if (connector->encoder == encoder) - intel_connector = to_intel_connector(connector); - - if (!intel_connector) { - ret = ASLC_BACKLIGHT_FAILED; - goto out; - } - DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp); - intel_panel_set_backlight(intel_connector, bclp, 255); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + intel_connector = to_intel_connector(connector); + panel = &intel_connector->panel; + if (panel->backlight.present) + intel_panel_set_backlight(intel_connector, bclp, 255); + } iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); -out: mutex_unlock(&dev->mode_config.mutex); - return ret; + + return 0; } static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index a98a990fbab3..a759ecdb7a6e 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1005,7 +1005,7 @@ static int intel_panel_fitter_pipe(struct drm_device *dev) u32 pfit_control; /* i830 doesn't have a panel fitter */ - if (IS_I830(dev)) + if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev))) return -1; pfit_control = I915_READ(PFIT_CONTROL); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e6f782d1c669..20ebc3e83d39 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -325,214 +325,170 @@ out: pipe_config->gmch_pfit.lvds_border_bits = border; } -static int is_backlight_combination_mode(struct drm_device *dev) +static int i915_panel_invert_brightness; +MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " + "(-1 force normal, 0 machine defaults, 1 force inversion), please " + "report PCI device ID, subsystem vendor and subsystem device ID " + "to dri-devel@lists.freedesktop.org, if your machine needs it. " + "It will then be included in an upcoming module version."); +module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); +static u32 intel_panel_compute_brightness(struct intel_connector *connector, + u32 val) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; - if (IS_GEN4(dev)) - return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; + WARN_ON(panel->backlight.max == 0); - if (IS_GEN2(dev)) - return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; + if (i915_panel_invert_brightness < 0) + return val; - return 0; + if (i915_panel_invert_brightness > 0 || + dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { + return panel->backlight.max - val; + } + + return val; } -/* XXX: query mode clock or hardware clock and program max PWM appropriately - * when it's 0. - */ -static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe) +static u32 bdw_get_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); - /* Restore the CTL value if it lost, e.g. GPU reset */ - - if (HAS_PCH_SPLIT(dev_priv->dev)) { - val = I915_READ(BLC_PWM_PCH_CTL2); - if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { - dev_priv->regfile.saveBLC_PWM_CTL2 = val; - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL2; - I915_WRITE(BLC_PWM_PCH_CTL2, val); - } - } else if (IS_VALLEYVIEW(dev)) { - val = I915_READ(VLV_BLC_PWM_CTL(pipe)); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(VLV_BLC_PWM_CTL2(pipe)); - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(VLV_BLC_PWM_CTL(pipe), val); - I915_WRITE(VLV_BLC_PWM_CTL2(pipe), - dev_priv->regfile.saveBLC_PWM_CTL2); - } + return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; +} - if (!val) - val = 0x0f42ffff; - } else { - val = I915_READ(BLC_PWM_CTL); - if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { - dev_priv->regfile.saveBLC_PWM_CTL = val; - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->regfile.saveBLC_PWM_CTL2 = - I915_READ(BLC_PWM_CTL2); - } else if (val == 0) { - val = dev_priv->regfile.saveBLC_PWM_CTL; - I915_WRITE(BLC_PWM_CTL, val); - if (INTEL_INFO(dev)->gen >= 4) - I915_WRITE(BLC_PWM_CTL2, - dev_priv->regfile.saveBLC_PWM_CTL2); - } - } +static u32 pch_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; - return val; + return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; } -static u32 intel_panel_get_max_backlight(struct drm_device *dev, - enum pipe pipe) +static u32 i9xx_get_backlight(struct intel_connector *connector) { - u32 max; + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 val; - max = i915_read_blc_pwm_ctl(dev, pipe); + val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + if (INTEL_INFO(dev)->gen < 4) + val >>= 1; - if (HAS_PCH_SPLIT(dev)) { - max >>= 16; - } else { - if (INTEL_INFO(dev)->gen < 4) - max >>= 17; - else - max >>= 16; + if (panel->backlight.combination_mode) { + u8 lbpc; - if (is_backlight_combination_mode(dev)) - max *= 0xff; + pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); + val *= lbpc; } - DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); - - return max; + return val; } -static int i915_panel_invert_brightness; -MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " - "(-1 force normal, 0 machine defaults, 1 force inversion), please " - "report PCI device ID, subsystem vendor and subsystem device ID " - "to dri-devel@lists.freedesktop.org, if your machine needs it. " - "It will then be included in an upcoming module version."); -module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); -static u32 intel_panel_compute_brightness(struct drm_device *dev, - enum pipe pipe, u32 val) +static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - if (i915_panel_invert_brightness < 0) - return val; + return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; +} - if (i915_panel_invert_brightness > 0 || - dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { - u32 max = intel_panel_get_max_backlight(dev, pipe); - if (max) - return max - val; - } +static u32 vlv_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + enum pipe pipe = intel_get_pipe_from_connector(connector); - return val; + return _vlv_get_backlight(dev, pipe); } -static u32 intel_panel_get_backlight(struct drm_device *dev, - enum pipe pipe) +static u32 intel_panel_get_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val; unsigned long flags; - int reg; - - spin_lock_irqsave(&dev_priv->backlight.lock, flags); - - if (IS_BROADWELL(dev)) { - val = I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; - } else if (HAS_PCH_SPLIT(dev)) { - val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; - } else { - if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL(pipe); - else - reg = BLC_PWM_CTL; - - val = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK; - if (INTEL_INFO(dev)->gen < 4) - val >>= 1; - if (is_backlight_combination_mode(dev)) { - u8 lbpc; - - pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); - val *= lbpc; - } - } + spin_lock_irqsave(&dev_priv->backlight_lock, flags); - val = intel_panel_compute_brightness(dev, pipe, val); + val = dev_priv->display.get_backlight(connector); + val = intel_panel_compute_brightness(connector, val); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); return val; } -static void intel_bdw_panel_set_backlight(struct drm_device *dev, u32 level) +static void bdw_set_backlight(struct intel_connector *connector, u32 level) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; I915_WRITE(BLC_PWM_PCH_CTL2, val | level); } -static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) +static void pch_set_backlight(struct intel_connector *connector, u32 level) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(BLC_PWM_CPU_CTL, val | level); + u32 tmp; + + tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); } -static void intel_panel_actually_set_backlight(struct drm_device *dev, - enum pipe pipe, u32 level) +static void i9xx_set_backlight(struct intel_connector *connector, u32 level) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 tmp; - int reg; + struct intel_panel *panel = &connector->panel; + u32 tmp, mask; - DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); - level = intel_panel_compute_brightness(dev, pipe, level); + WARN_ON(panel->backlight.max == 0); - if (IS_BROADWELL(dev)) - return intel_bdw_panel_set_backlight(dev, level); - else if (HAS_PCH_SPLIT(dev)) - return intel_pch_panel_set_backlight(dev, level); - - if (is_backlight_combination_mode(dev)) { - u32 max = intel_panel_get_max_backlight(dev, pipe); + if (panel->backlight.combination_mode) { u8 lbpc; - /* we're screwed, but keep behaviour backwards compatible */ - if (!max) - max = 1; - - lbpc = level * 0xfe / max + 1; + lbpc = level * 0xfe / panel->backlight.max + 1; level /= lbpc; pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); } - if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL(pipe); - else - reg = BLC_PWM_CTL; - - tmp = I915_READ(reg); - if (INTEL_INFO(dev)->gen < 4) + if (IS_GEN4(dev)) { + mask = BACKLIGHT_DUTY_CYCLE_MASK; + } else { level <<= 1; - tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(reg, tmp | level); + mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; + } + + tmp = I915_READ(BLC_PWM_CTL) & ~mask; + I915_WRITE(BLC_PWM_CTL, tmp | level); +} + +static void vlv_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); +} + +static void +intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); + + level = intel_panel_compute_brightness(connector, level); + dev_priv->display.set_backlight(connector, level); } /* set backlight brightness to level in range [0..max] */ @@ -541,6 +497,7 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); u32 freq; unsigned long flags; @@ -548,34 +505,77 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level, if (pipe == INVALID_PIPE) return; - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); - freq = intel_panel_get_max_backlight(dev, pipe); - if (!freq) { - /* we are screwed, bail out */ - goto out; - } + WARN_ON(panel->backlight.max == 0); - /* scale to hardware, but be careful to not overflow */ + /* scale to hardware max, but be careful to not overflow */ + freq = panel->backlight.max; if (freq < max) level = level * freq / max; else level = freq / max * level; - dev_priv->backlight.level = level; - if (dev_priv->backlight.device) - dev_priv->backlight.device->props.brightness = level; + panel->backlight.level = level; + if (panel->backlight.device) + panel->backlight.device->props.brightness = level; - if (dev_priv->backlight.enabled) - intel_panel_actually_set_backlight(dev, pipe, level); -out: - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + if (panel->backlight.enabled) + intel_panel_actually_set_backlight(connector, level); + + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); +} + +static void pch_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); + + tmp = I915_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); +} + +static void i9xx_disable_backlight(struct intel_connector *connector) +{ + intel_panel_actually_set_backlight(connector, 0); +} + +static void i965_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); +} + +static void vlv_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); } void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); unsigned long flags; @@ -593,150 +593,215 @@ void intel_panel_disable_backlight(struct intel_connector *connector) return; } - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + spin_lock_irqsave(&dev_priv->backlight_lock, flags); - dev_priv->backlight.enabled = false; - intel_panel_actually_set_backlight(dev, pipe, 0); + panel->backlight.enabled = false; + dev_priv->display.disable_backlight(connector); - if (INTEL_INFO(dev)->gen >= 4) { - uint32_t reg, tmp; + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); +} - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL2; - else if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL2(pipe); - else - reg = BLC_PWM_CTL2; +static void bdw_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 pch_ctl1, pch_ctl2; + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + DRM_DEBUG_KMS("pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + } - I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); + pch_ctl2 = panel->backlight.max << 16; + I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); - if (HAS_PCH_SPLIT(dev)) { - tmp = I915_READ(BLC_PWM_PCH_CTL1); - tmp &= ~BLM_PCH_PWM_ENABLE; - I915_WRITE(BLC_PWM_PCH_CTL1, tmp); - } - } + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + + /* BDW always uses the pch pwm controls. */ + pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; + + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + POSTING_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + /* This won't stick until the above enable. */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); } -void intel_panel_enable_backlight(struct intel_connector *connector) +static void pch_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; enum pipe pipe = intel_get_pipe_from_connector(connector); enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); - unsigned long flags; + u32 cpu_ctl2, pch_ctl1, pch_ctl2; - if (pipe == INVALID_PIPE) - return; + cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); + if (cpu_ctl2 & BLM_PWM_ENABLE) { + WARN(1, "cpu backlight already enabled\n"); + cpu_ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); + } - DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { + DRM_DEBUG_KMS("pch backlight already enabled\n"); + pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + } + + if (cpu_transcoder == TRANSCODER_EDP) + cpu_ctl2 = BLM_TRANSCODER_EDP; + else + cpu_ctl2 = BLM_PIPE(cpu_transcoder); + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); + POSTING_READ(BLC_PWM_CPU_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); + + /* This won't stick until the above enable. */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); - spin_lock_irqsave(&dev_priv->backlight.lock, flags); + pch_ctl2 = panel->backlight.max << 16; + I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); - if (dev_priv->backlight.level == 0) { - dev_priv->backlight.level = intel_panel_get_max_backlight(dev, - pipe); - if (dev_priv->backlight.device) - dev_priv->backlight.device->props.brightness = - dev_priv->backlight.level; + pch_ctl1 = 0; + if (panel->backlight.active_low_pwm) + pch_ctl1 |= BLM_PCH_POLARITY; + + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); + POSTING_READ(BLC_PWM_PCH_CTL1); + I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); +} + +static void i9xx_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 ctl, freq; + + ctl = I915_READ(BLC_PWM_CTL); + if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { + WARN(1, "backlight already enabled\n"); + I915_WRITE(BLC_PWM_CTL, 0); } - if (INTEL_INFO(dev)->gen >= 4) { - uint32_t reg, tmp; + freq = panel->backlight.max; + if (panel->backlight.combination_mode) + freq /= 0xff; - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL2; - else if (IS_VALLEYVIEW(dev)) - reg = VLV_BLC_PWM_CTL2(pipe); - else - reg = BLC_PWM_CTL2; + ctl = freq << 17; + if (IS_GEN2(dev) && panel->backlight.combination_mode) + ctl |= BLM_LEGACY_MODE; + if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) + ctl |= BLM_POLARITY_PNV; - tmp = I915_READ(reg); + I915_WRITE(BLC_PWM_CTL, ctl); + POSTING_READ(BLC_PWM_CTL); - /* Note that this can also get called through dpms changes. And - * we don't track the backlight dpms state, hence check whether - * we have to do anything first. */ - if (tmp & BLM_PWM_ENABLE) - goto set_level; + /* XXX: combine this into above write? */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} - if (INTEL_INFO(dev)->num_pipes == 3) - tmp &= ~BLM_PIPE_SELECT_IVB; - else - tmp &= ~BLM_PIPE_SELECT; +static void i965_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 ctl, ctl2, freq; - if (cpu_transcoder == TRANSCODER_EDP) - tmp |= BLM_TRANSCODER_EDP; - else - tmp |= BLM_PIPE(cpu_transcoder); - tmp &= ~BLM_PWM_ENABLE; - - I915_WRITE(reg, tmp); - POSTING_READ(reg); - I915_WRITE(reg, tmp | BLM_PWM_ENABLE); - - if (IS_BROADWELL(dev)) { - /* - * Broadwell requires PCH override to drive the PCH - * backlight pin. The above will configure the CPU - * backlight pin, which we don't plan to use. - */ - tmp = I915_READ(BLC_PWM_PCH_CTL1); - tmp |= BLM_PCH_OVERRIDE_ENABLE | BLM_PCH_PWM_ENABLE; - I915_WRITE(BLC_PWM_PCH_CTL1, tmp); - } else if (HAS_PCH_SPLIT(dev) && - !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { - tmp = I915_READ(BLC_PWM_PCH_CTL1); - tmp |= BLM_PCH_PWM_ENABLE; - tmp &= ~BLM_PCH_OVERRIDE_ENABLE; - I915_WRITE(BLC_PWM_PCH_CTL1, tmp); - } + ctl2 = I915_READ(BLC_PWM_CTL2); + if (ctl2 & BLM_PWM_ENABLE) { + WARN(1, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(BLC_PWM_CTL2, ctl2); } -set_level: - /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. - * BLC_PWM_CPU_CTL may be cleared to zero automatically when these - * registers are set. - */ - dev_priv->backlight.enabled = true; - intel_panel_actually_set_backlight(dev, pipe, - dev_priv->backlight.level); + freq = panel->backlight.max; + if (panel->backlight.combination_mode) + freq /= 0xff; + + ctl = freq << 16; + I915_WRITE(BLC_PWM_CTL, ctl); + + /* XXX: combine this into above write? */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + ctl2 = BLM_PIPE(pipe); + if (panel->backlight.combination_mode) + ctl2 |= BLM_COMBINATION_MODE; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + I915_WRITE(BLC_PWM_CTL2, ctl2); + POSTING_READ(BLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); } -/* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */ -static void intel_panel_init_backlight_regs(struct drm_device *dev) +static void vlv_enable_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 ctl, ctl2; - if (IS_VALLEYVIEW(dev)) { - enum pipe pipe; + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); + if (ctl2 & BLM_PWM_ENABLE) { + WARN(1, "backlight already enabled\n"); + ctl2 &= ~BLM_PWM_ENABLE; + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); + } - for_each_pipe(pipe) { - u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); + ctl = panel->backlight.max << 16; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); - /* Skip if the modulation freq is already set */ - if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) - continue; + /* XXX: combine this into above write? */ + intel_panel_actually_set_backlight(connector, panel->backlight.level); - cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | - cur_val); - } - } + ctl2 = 0; + if (panel->backlight.active_low_pwm) + ctl2 |= BLM_POLARITY_I965; + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); + POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); + I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); } -static void intel_panel_init_backlight(struct drm_device *dev) +void intel_panel_enable_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe = intel_get_pipe_from_connector(connector); + unsigned long flags; + + if (pipe == INVALID_PIPE) + return; + + DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); + + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + + WARN_ON(panel->backlight.max == 0); + + if (panel->backlight.level == 0) { + panel->backlight.level = panel->backlight.max; + if (panel->backlight.device) + panel->backlight.device->props.brightness = + panel->backlight.level; + } - intel_panel_init_backlight_regs(dev); + dev_priv->display.enable_backlight(connector); + panel->backlight.enabled = true; - dev_priv->backlight.level = intel_panel_get_backlight(dev, 0); - dev_priv->backlight.enabled = dev_priv->backlight.level != 0; + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); } enum drm_connector_status @@ -762,7 +827,7 @@ intel_panel_detect(struct drm_device *dev) } #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) -static int intel_panel_update_status(struct backlight_device *bd) +static int intel_backlight_device_update_status(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; @@ -776,85 +841,362 @@ static int intel_panel_update_status(struct backlight_device *bd) return 0; } -static int intel_panel_get_brightness(struct backlight_device *bd) +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; - enum pipe pipe; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + intel_runtime_pm_get(dev_priv); mutex_lock(&dev->mode_config.mutex); - pipe = intel_get_pipe_from_connector(connector); + ret = intel_panel_get_backlight(connector); mutex_unlock(&dev->mode_config.mutex); - if (pipe == INVALID_PIPE) - return 0; + intel_runtime_pm_put(dev_priv); - return intel_panel_get_backlight(connector->base.dev, pipe); + return ret; } -static const struct backlight_ops intel_panel_bl_ops = { - .update_status = intel_panel_update_status, - .get_brightness = intel_panel_get_brightness, +static const struct backlight_ops intel_backlight_device_ops = { + .update_status = intel_backlight_device_update_status, + .get_brightness = intel_backlight_device_get_brightness, }; -int intel_panel_setup_backlight(struct drm_connector *connector) +static int intel_backlight_device_register(struct intel_connector *connector) { - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; struct backlight_properties props; - unsigned long flags; - intel_panel_init_backlight(dev); - - if (WARN_ON(dev_priv->backlight.device)) + if (WARN_ON(panel->backlight.device)) return -ENODEV; + BUG_ON(panel->backlight.max == 0); + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; - props.brightness = dev_priv->backlight.level; + props.brightness = panel->backlight.level; + props.max_brightness = panel->backlight.max; - spin_lock_irqsave(&dev_priv->backlight.lock, flags); - props.max_brightness = intel_panel_get_max_backlight(dev, 0); - spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); - - if (props.max_brightness == 0) { - DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); - return -ENODEV; - } - dev_priv->backlight.device = + /* + * Note: using the same name independent of the connector prevents + * registration of multiple backlight devices in the driver. + */ + panel->backlight.device = backlight_device_register("intel_backlight", - connector->kdev, - to_intel_connector(connector), - &intel_panel_bl_ops, &props); + connector->base.kdev, + connector, + &intel_backlight_device_ops, &props); - if (IS_ERR(dev_priv->backlight.device)) { + if (IS_ERR(panel->backlight.device)) { DRM_ERROR("Failed to register backlight: %ld\n", - PTR_ERR(dev_priv->backlight.device)); - dev_priv->backlight.device = NULL; + PTR_ERR(panel->backlight.device)); + panel->backlight.device = NULL; return -ENODEV; } return 0; } -void intel_panel_destroy_backlight(struct drm_device *dev) +static void intel_backlight_device_unregister(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + if (panel->backlight.device) { + backlight_device_unregister(panel->backlight.device); + panel->backlight.device = NULL; + } +} +#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ +static int intel_backlight_device_register(struct intel_connector *connector) +{ + return 0; +} +static void intel_backlight_device_unregister(struct intel_connector *connector) +{ +} +#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ + +/* + * Note: The setup hooks can't assume pipe is set! + * + * XXX: Query mode clock or hardware clock and program PWM modulation frequency + * appropriately when it's 0. Use VBT and/or sane defaults. + */ +static int bdw_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 pch_ctl1, pch_ctl2, val; + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); + panel->backlight.max = pch_ctl2 >> 16; + if (!panel->backlight.max) + return -ENODEV; + + val = bdw_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; +} + +static int pch_setup_backlight(struct intel_connector *connector) { + struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight.device) { - backlight_device_unregister(dev_priv->backlight.device); - dev_priv->backlight.device = NULL; + struct intel_panel *panel = &connector->panel; + u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; + + pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); + panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; + + pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); + panel->backlight.max = pch_ctl2 >> 16; + if (!panel->backlight.max) + return -ENODEV; + + val = pch_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); + panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && + (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; + + return 0; +} + +static int i9xx_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 ctl, val; + + ctl = I915_READ(BLC_PWM_CTL); + + if (IS_GEN2(dev)) + panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; + + if (IS_PINEVIEW(dev)) + panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; + + panel->backlight.max = ctl >> 17; + if (panel->backlight.combination_mode) + panel->backlight.max *= 0xff; + + if (!panel->backlight.max) + return -ENODEV; + + val = i9xx_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; +} + +static int i965_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 ctl, ctl2, val; + + ctl2 = I915_READ(BLC_PWM_CTL2); + panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = I915_READ(BLC_PWM_CTL); + panel->backlight.max = ctl >> 16; + if (panel->backlight.combination_mode) + panel->backlight.max *= 0xff; + + if (!panel->backlight.max) + return -ENODEV; + + val = i9xx_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; +} + +static int vlv_setup_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + enum pipe pipe; + u32 ctl, ctl2, val; + + for_each_pipe(pipe) { + u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); + + /* Skip if the modulation freq is already set */ + if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) + continue; + + cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | + cur_val); } + + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); + panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; + + ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); + panel->backlight.max = ctl >> 16; + if (!panel->backlight.max) + return -ENODEV; + + val = _vlv_get_backlight(dev, PIPE_A); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; } -#else + int intel_panel_setup_backlight(struct drm_connector *connector) { - intel_panel_init_backlight(connector->dev); + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; + unsigned long flags; + int ret; + + /* set level and max in panel struct */ + spin_lock_irqsave(&dev_priv->backlight_lock, flags); + ret = dev_priv->display.setup_backlight(intel_connector); + spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); + + if (ret) { + DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", + drm_get_connector_name(connector)); + return ret; + } + + intel_backlight_device_register(intel_connector); + + panel->backlight.present = true; + + DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, " + "sysfs interface %sregistered\n", + panel->backlight.enabled ? "enabled" : "disabled", + panel->backlight.level, panel->backlight.max, + panel->backlight.device ? "" : "not "); + return 0; } -void intel_panel_destroy_backlight(struct drm_device *dev) +void intel_panel_destroy_backlight(struct drm_connector *connector) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_panel *panel = &intel_connector->panel; + + panel->backlight.present = false; + 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) { - return; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_BROADWELL(dev)) { + dev_priv->display.setup_backlight = bdw_setup_backlight; + dev_priv->display.enable_backlight = bdw_enable_backlight; + dev_priv->display.disable_backlight = pch_disable_backlight; + dev_priv->display.set_backlight = bdw_set_backlight; + dev_priv->display.get_backlight = bdw_get_backlight; + } else if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.setup_backlight = pch_setup_backlight; + dev_priv->display.enable_backlight = pch_enable_backlight; + dev_priv->display.disable_backlight = pch_disable_backlight; + dev_priv->display.set_backlight = pch_set_backlight; + dev_priv->display.get_backlight = pch_get_backlight; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.setup_backlight = vlv_setup_backlight; + dev_priv->display.enable_backlight = vlv_enable_backlight; + dev_priv->display.disable_backlight = vlv_disable_backlight; + dev_priv->display.set_backlight = vlv_set_backlight; + dev_priv->display.get_backlight = vlv_get_backlight; + } else if (IS_GEN4(dev)) { + dev_priv->display.setup_backlight = i965_setup_backlight; + dev_priv->display.enable_backlight = i965_enable_backlight; + dev_priv->display.disable_backlight = i965_disable_backlight; + dev_priv->display.set_backlight = i9xx_set_backlight; + dev_priv->display.get_backlight = i9xx_get_backlight; + } else { + dev_priv->display.setup_backlight = i9xx_setup_backlight; + dev_priv->display.enable_backlight = i9xx_enable_backlight; + dev_priv->display.disable_backlight = i9xx_disable_backlight; + dev_priv->display.set_backlight = i9xx_set_backlight; + dev_priv->display.get_backlight = i9xx_get_backlight; + } } -#endif int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode) @@ -871,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 26c29c173221..d77cc81900f9 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... */ @@ -191,7 +197,11 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) u32 blt_ecoskpd; /* Make sure blitter notifies FBC of writes */ - gen6_gt_force_wake_get(dev_priv); + + /* Blitter is part of Media powerwell on VLV. No impact of + * his param in other platforms for now */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA); + blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << GEN6_BLITTER_LOCK_SHIFT; @@ -202,10 +212,11 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) GEN6_BLITTER_LOCK_SHIFT); I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); POSTING_READ(GEN6_BLITTER_ECOSKPD); - gen6_gt_force_wake_put(dev_priv); + + 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; @@ -214,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); @@ -222,12 +232,11 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); /* Set persistent mode for front-buffer rendering, ala X. */ dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; - dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg); + dpfc_ctl |= DPFC_CTL_FENCE_EN; + if (IS_GEN5(dev)) + 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... */ @@ -265,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; @@ -295,7 +304,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) sandybridge_blit_fbc_update(dev); - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } bool intel_fbc_enabled(struct drm_device *dev) @@ -322,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; @@ -360,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; @@ -374,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; @@ -454,7 +461,7 @@ void intel_update_fbc(struct drm_device *dev) const struct drm_display_mode *adjusted_mode; unsigned int max_width, max_height; - if (!I915_HAS_FBC(dev)) { + if (!HAS_FBC(dev)) { set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED); return; } @@ -530,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; } @@ -595,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; @@ -817,7 +824,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane) return size; } -static int i85x_get_fifo_size(struct drm_device *dev, int plane) +static int i830_get_fifo_size(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dsparb = I915_READ(DSPARB); @@ -850,21 +857,6 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane) return size; } -static int i830_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - size >>= 1; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - /* Pineview has different values for various configs */ static const struct intel_watermark_params pineview_display_wm = { PINEVIEW_DISPLAY_FIFO, @@ -943,14 +935,14 @@ static const struct intel_watermark_params i915_wm_info = { 2, I915_FIFO_LINE_SIZE }; -static const struct intel_watermark_params i855_wm_info = { +static const struct intel_watermark_params i830_wm_info = { I855GM_FIFO_SIZE, I915_MAX_WM, 1, 2, I830_FIFO_LINE_SIZE }; -static const struct intel_watermark_params i830_wm_info = { +static const struct intel_watermark_params i845_wm_info = { I830_FIFO_SIZE, I915_MAX_WM, 1, @@ -958,65 +950,6 @@ static const struct intel_watermark_params i830_wm_info = { I830_FIFO_LINE_SIZE }; -static const struct intel_watermark_params ironlake_display_wm_info = { - ILK_DISPLAY_FIFO, - ILK_DISPLAY_MAXWM, - ILK_DISPLAY_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_wm_info = { - ILK_CURSOR_FIFO, - ILK_CURSOR_MAXWM, - ILK_CURSOR_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_display_srwm_info = { - ILK_DISPLAY_SR_FIFO, - ILK_DISPLAY_MAX_SRWM, - ILK_DISPLAY_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_srwm_info = { - ILK_CURSOR_SR_FIFO, - ILK_CURSOR_MAX_SRWM, - ILK_CURSOR_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; - -static const struct intel_watermark_params sandybridge_display_wm_info = { - SNB_DISPLAY_FIFO, - SNB_DISPLAY_MAXWM, - SNB_DISPLAY_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_wm_info = { - SNB_CURSOR_FIFO, - SNB_CURSOR_MAXWM, - SNB_CURSOR_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_display_srwm_info = { - SNB_DISPLAY_SR_FIFO, - SNB_DISPLAY_MAX_SRWM, - SNB_DISPLAY_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_srwm_info = { - SNB_CURSOR_SR_FIFO, - SNB_CURSOR_MAX_SRWM, - SNB_CURSOR_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; - - /** * intel_calculate_wm - calculate watermark level * @clock_in_khz: pixel clock @@ -1567,7 +1500,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) else if (!IS_GEN2(dev)) wm_info = &i915_wm_info; else - wm_info = &i855_wm_info; + wm_info = &i830_wm_info; fifo_size = dev_priv->display.get_fifo_size(dev, 0); crtc = intel_get_crtc_for_plane(dev, 0); @@ -1615,7 +1548,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) if (IS_I945G(dev) || IS_I945GM(dev)) I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0); else if (IS_I915GM(dev)) - I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); + I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_SELF_EN)); /* Calc sr entries for one plane configs */ if (HAS_FW_BLC(dev) && enabled) { @@ -1667,14 +1600,14 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); else if (IS_I915GM(dev)) - I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); + I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_SELF_EN)); DRM_DEBUG_KMS("memory self refresh enabled\n"); } else DRM_DEBUG_KMS("memory self refresh disabled\n"); } } -static void i830_update_wm(struct drm_crtc *unused_crtc) +static void i845_update_wm(struct drm_crtc *unused_crtc) { struct drm_device *dev = unused_crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1689,7 +1622,7 @@ static void i830_update_wm(struct drm_crtc *unused_crtc) adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock, - &i830_wm_info, + &i845_wm_info, dev_priv->display.get_fifo_size(dev, 0), 4, latency_ns); fwater_lo = I915_READ(FW_BLC) & ~0xfff; @@ -1700,423 +1633,6 @@ static void i830_update_wm(struct drm_crtc *unused_crtc) I915_WRITE(FW_BLC, fwater_lo); } -/* - * Check the wm result. - * - * If any calculated watermark values is larger than the maximum value that - * can be programmed into the associated watermark register, that watermark - * must be disabled. - */ -static bool ironlake_check_srwm(struct drm_device *dev, int level, - int fbc_wm, int display_wm, int cursor_wm, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," - " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); - - if (fbc_wm > SNB_FBC_MAX_SRWM) { - DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", - fbc_wm, SNB_FBC_MAX_SRWM, level); - - /* fbc has it's own way to disable FBC WM */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); - return false; - } else if (INTEL_INFO(dev)->gen >= 6) { - /* enable FBC WM (except on ILK, where it must remain off) */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS); - } - - if (display_wm > display->max_wm) { - DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", - display_wm, SNB_DISPLAY_MAX_SRWM, level); - return false; - } - - if (cursor_wm > cursor->max_wm) { - DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", - cursor_wm, SNB_CURSOR_MAX_SRWM, level); - return false; - } - - if (!(fbc_wm || display_wm || cursor_wm)) { - DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); - return false; - } - - return true; -} - -/* - * Compute watermark values of WM[1-3], - */ -static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, - int latency_ns, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor, - int *fbc_wm, int *display_wm, int *cursor_wm) -{ - struct drm_crtc *crtc; - const struct drm_display_mode *adjusted_mode; - unsigned long line_time_us; - int hdisplay, htotal, pixel_size, clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *fbc_wm = *display_wm = *cursor_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; - clock = adjusted_mode->crtc_clock; - htotal = adjusted_mode->crtc_htotal; - hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; - pixel_size = crtc->fb->bits_per_pixel / 8; - - line_time_us = (htotal * 1000) / clock; - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *display_wm = entries + display->guard_size; - - /* - * Spec says: - * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 - */ - *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = DIV_ROUND_UP(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - - return ironlake_check_srwm(dev, level, - *fbc_wm, *display_wm, *cursor_wm, - display, cursor); -} - -static void ironlake_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, PIPE_A, - &ironlake_display_wm_info, - dev_priv->wm.pri_latency[0] * 100, - &ironlake_cursor_wm_info, - dev_priv->wm.cur_latency[0] * 100, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEA_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_A; - } - - if (g4x_compute_wm0(dev, PIPE_B, - &ironlake_display_wm_info, - dev_priv->wm.pri_latency[0] * 100, - &ironlake_cursor_wm_info, - dev_priv->wm.cur_latency[0] * 100, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEB_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_B; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled)) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - dev_priv->wm.pri_latency[1] * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - dev_priv->wm.pri_latency[2] * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* - * WM3 is unsupported on ILK, probably because we don't have latency - * data for that power state - */ -} - -static void sandybridge_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = dev_priv->wm.pri_latency[0] * 100; /* In unit 0.1us */ - u32 val; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, PIPE_A, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEA_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEA_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_A; - } - - if (g4x_compute_wm0(dev, PIPE_B, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEB_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEB_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_B; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - * - * SNB support 3 levels of watermark. - * - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, - * and disabled in the descending order - * - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled) || - dev_priv->sprite_scaling_enabled) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - dev_priv->wm.pri_latency[1] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - dev_priv->wm.pri_latency[2] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM3 */ - if (!ironlake_compute_srwm(dev, 3, enabled, - dev_priv->wm.pri_latency[3] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM3_LP_ILK, - WM3_LP_EN | - (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); -} - -static void ivybridge_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = dev_priv->wm.pri_latency[0] * 100; /* In unit 0.1us */ - u32 val; - int fbc_wm, plane_wm, cursor_wm; - int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, PIPE_A, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEA_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEA_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_A; - } - - if (g4x_compute_wm0(dev, PIPE_B, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEB_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEB_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_B; - } - - if (g4x_compute_wm0(dev, PIPE_C, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEC_IVB); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEC_IVB, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe C -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1 << PIPE_C; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - * - * SNB support 3 levels of watermark. - * - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, - * and disabled in the descending order - * - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled) || - dev_priv->sprite_scaling_enabled) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - dev_priv->wm.pri_latency[1] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - dev_priv->wm.pri_latency[2] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM3, note we have to correct the cursor latency */ - if (!ironlake_compute_srwm(dev, 3, enabled, - dev_priv->wm.pri_latency[3] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &ignore_cursor_wm) || - !ironlake_compute_srwm(dev, 3, enabled, - dev_priv->wm.cur_latency[3] * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM3_LP_ILK, - WM3_LP_EN | - (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); -} - static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev, struct drm_crtc *crtc) { @@ -2185,7 +1701,7 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; } -struct hsw_pipe_wm_parameters { +struct ilk_pipe_wm_parameters { bool active; uint32_t pipe_htotal; uint32_t pixel_rate; @@ -2194,7 +1710,7 @@ struct hsw_pipe_wm_parameters { struct intel_plane_wm_parameters cur; }; -struct hsw_wm_maximums { +struct ilk_wm_maximums { uint16_t pri; uint16_t spr; uint16_t cur; @@ -2212,7 +1728,7 @@ struct intel_wm_config { * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. */ -static uint32_t ilk_compute_pri_wm(const struct hsw_pipe_wm_parameters *params, +static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params, uint32_t mem_value, bool is_lp) { @@ -2241,7 +1757,7 @@ static uint32_t ilk_compute_pri_wm(const struct hsw_pipe_wm_parameters *params, * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. */ -static uint32_t ilk_compute_spr_wm(const struct hsw_pipe_wm_parameters *params, +static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params, uint32_t mem_value) { uint32_t method1, method2; @@ -2264,7 +1780,7 @@ static uint32_t ilk_compute_spr_wm(const struct hsw_pipe_wm_parameters *params, * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. */ -static uint32_t ilk_compute_cur_wm(const struct hsw_pipe_wm_parameters *params, +static uint32_t ilk_compute_cur_wm(const struct ilk_pipe_wm_parameters *params, uint32_t mem_value) { if (!params->active || !params->cur.enabled) @@ -2278,7 +1794,7 @@ static uint32_t ilk_compute_cur_wm(const struct hsw_pipe_wm_parameters *params, } /* Only for WM_LP. */ -static uint32_t ilk_compute_fbc_wm(const struct hsw_pipe_wm_parameters *params, +static uint32_t ilk_compute_fbc_wm(const struct ilk_pipe_wm_parameters *params, uint32_t pri_val) { if (!params->active || !params->pri.enabled) @@ -2383,7 +1899,7 @@ static void ilk_compute_wm_maximums(struct drm_device *dev, int level, const struct intel_wm_config *config, enum intel_ddb_partitioning ddb_partitioning, - struct hsw_wm_maximums *max) + struct ilk_wm_maximums *max) { max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false); max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true); @@ -2392,7 +1908,7 @@ static void ilk_compute_wm_maximums(struct drm_device *dev, } static bool ilk_validate_wm_level(int level, - const struct hsw_wm_maximums *max, + const struct ilk_wm_maximums *max, struct intel_wm_level *result) { bool ret; @@ -2434,7 +1950,7 @@ static bool ilk_validate_wm_level(int level, static void ilk_compute_wm_level(struct drm_i915_private *dev_priv, int level, - const struct hsw_pipe_wm_parameters *p, + const struct ilk_pipe_wm_parameters *p, struct intel_wm_level *result) { uint16_t pri_latency = dev_priv->wm.pri_latency[level]; @@ -2482,7 +1998,7 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[5]) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_HASWELL(dev)) { + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { uint64_t sskpd = I915_READ64(MCH_SSKPD); wm[0] = (sskpd >> 56) & 0xFF; @@ -2530,7 +2046,7 @@ static void intel_fixup_cur_wm_latency(struct drm_device *dev, uint16_t wm[5]) static int ilk_wm_max_level(const struct drm_device *dev) { /* how many WM levels are we expecting */ - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) return 4; else if (INTEL_INFO(dev)->gen >= 6) return 3; @@ -2582,8 +2098,8 @@ static void intel_setup_wm_latency(struct drm_device *dev) intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency); } -static void hsw_compute_wm_parameters(struct drm_crtc *crtc, - struct hsw_pipe_wm_parameters *p, +static void ilk_compute_wm_parameters(struct drm_crtc *crtc, + struct ilk_pipe_wm_parameters *p, struct intel_wm_config *config) { struct drm_device *dev = crtc->dev; @@ -2593,7 +2109,7 @@ static void hsw_compute_wm_parameters(struct drm_crtc *crtc, p->active = intel_crtc_active(crtc); if (p->active) { - p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal; + p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal; p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8; p->cur.bytes_per_pixel = 4; @@ -2620,7 +2136,7 @@ static void hsw_compute_wm_parameters(struct drm_crtc *crtc, /* Compute new watermarks for the pipe */ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, - const struct hsw_pipe_wm_parameters *params, + const struct ilk_pipe_wm_parameters *params, struct intel_pipe_wm *pipe_wm) { struct drm_device *dev = crtc->dev; @@ -2632,16 +2148,25 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, .sprites_enabled = params->spr.enabled, .sprites_scaled = params->spr.scaled, }; - struct hsw_wm_maximums max; + struct ilk_wm_maximums max; /* LP0 watermarks always use 1/2 DDB partitioning */ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); + /* ILK/SNB: LP2+ watermarks only w/o sprites */ + if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled) + max_level = 1; + + /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */ + if (params->spr.scaled) + max_level = 0; + for (level = 0; level <= max_level; level++) ilk_compute_wm_level(dev_priv, level, params, &pipe_wm->wm[level]); - pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); /* At least LP0 must be valid */ return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]); @@ -2676,12 +2201,19 @@ static void ilk_merge_wm_level(struct drm_device *dev, * Merge all low power watermarks for all active pipes. */ static void ilk_wm_merge(struct drm_device *dev, - const struct hsw_wm_maximums *max, + const struct intel_wm_config *config, + const struct ilk_wm_maximums *max, struct intel_pipe_wm *merged) { int level, max_level = ilk_wm_max_level(dev); - merged->fbc_wm_enabled = true; + /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */ + if ((INTEL_INFO(dev)->gen <= 6 || IS_IVYBRIDGE(dev)) && + config->num_pipes_active > 1) + return; + + /* ILK: FBC WM must be disabled always */ + merged->fbc_wm_enabled = INTEL_INFO(dev)->gen >= 6; /* merge each WM1+ level */ for (level = 1; level <= max_level; level++) { @@ -2701,6 +2233,20 @@ static void ilk_wm_merge(struct drm_device *dev, wm->fbc_val = 0; } } + + /* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */ + /* + * FIXME this is racy. FBC might get enabled later. + * What we should check here is whether FBC can be + * enabled sometime later. + */ + if (IS_GEN5(dev) && !merged->fbc_wm_enabled && intel_fbc_enabled(dev)) { + for (level = 2; level <= max_level; level++) { + struct intel_wm_level *wm = &merged->wm[level]; + + wm->enable = false; + } + } } static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) @@ -2709,10 +2255,21 @@ static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm) return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable); } -static void hsw_compute_wm_results(struct drm_device *dev, +/* The value we need to program into the WM_LPx latency field */ +static unsigned int ilk_wm_lp_latency(struct drm_device *dev, int level) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + return 2 * level; + else + return dev_priv->wm.pri_latency[level]; +} + +static void ilk_compute_wm_results(struct drm_device *dev, const struct intel_pipe_wm *merged, enum intel_ddb_partitioning partitioning, - struct hsw_wm_values *results) + struct ilk_wm_values *results) { struct intel_crtc *intel_crtc; int level, wm_lp; @@ -2731,7 +2288,7 @@ static void hsw_compute_wm_results(struct drm_device *dev, break; results->wm_lp[wm_lp - 1] = WM3_LP_EN | - ((level * 2) << WM1_LP_LATENCY_SHIFT) | + (ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT) | (r->pri_val << WM1_LP_SR_SHIFT) | r->cur_val; @@ -2742,7 +2299,11 @@ static void hsw_compute_wm_results(struct drm_device *dev, results->wm_lp[wm_lp - 1] |= r->fbc_val << WM1_LP_FBC_SHIFT; - results->wm_lp_spr[wm_lp - 1] = r->spr_val; + if (INTEL_INFO(dev)->gen <= 6 && r->spr_val) { + WARN_ON(wm_lp != 1); + results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val; + } else + results->wm_lp_spr[wm_lp - 1] = r->spr_val; } /* LP0 register values */ @@ -2765,7 +2326,7 @@ static void hsw_compute_wm_results(struct drm_device *dev, /* Find the result with the highest level enabled. Check for enable_fbc_wm in * case both are at the same level. Prefer r1 in case they're the same. */ -static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev, +static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev, struct intel_pipe_wm *r1, struct intel_pipe_wm *r2) { @@ -2800,8 +2361,8 @@ static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev, #define WM_DIRTY_DDB (1 << 25) static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, - const struct hsw_wm_values *old, - const struct hsw_wm_values *new) + const struct ilk_wm_values *old, + const struct ilk_wm_values *new) { unsigned int dirty = 0; enum pipe pipe; @@ -2851,27 +2412,53 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev, return dirty; } +static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv, + unsigned int dirty) +{ + struct ilk_wm_values *previous = &dev_priv->wm.hw; + bool changed = false; + + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) { + previous->wm_lp[2] &= ~WM1_LP_SR_EN; + I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]); + changed = true; + } + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) { + previous->wm_lp[1] &= ~WM1_LP_SR_EN; + I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]); + changed = true; + } + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) { + previous->wm_lp[0] &= ~WM1_LP_SR_EN; + I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]); + changed = true; + } + + /* + * Don't touch WM1S_LP_EN here. + * Doing so could cause underruns. + */ + + return changed; +} + /* * The spec says we shouldn't write when we don't need, because every write * causes WMs to be re-evaluated, expending some power. */ -static void hsw_write_wm_values(struct drm_i915_private *dev_priv, - struct hsw_wm_values *results) +static void ilk_write_wm_values(struct drm_i915_private *dev_priv, + struct ilk_wm_values *results) { - struct hsw_wm_values *previous = &dev_priv->wm.hw; + struct drm_device *dev = dev_priv->dev; + struct ilk_wm_values *previous = &dev_priv->wm.hw; unsigned int dirty; uint32_t val; - dirty = ilk_compute_wm_dirty(dev_priv->dev, previous, results); + dirty = ilk_compute_wm_dirty(dev, previous, results); if (!dirty) return; - if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != 0) - I915_WRITE(WM3_LP_ILK, 0); - if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != 0) - I915_WRITE(WM2_LP_ILK, 0); - if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != 0) - I915_WRITE(WM1_LP_ILK, 0); + _ilk_disable_lp_wm(dev_priv, dirty); if (dirty & WM_DIRTY_PIPE(PIPE_A)) I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); @@ -2888,12 +2475,21 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]); if (dirty & WM_DIRTY_DDB) { - val = I915_READ(WM_MISC); - if (results->partitioning == INTEL_DDB_PART_1_2) - val &= ~WM_MISC_DATA_PARTITION_5_6; - else - val |= WM_MISC_DATA_PARTITION_5_6; - I915_WRITE(WM_MISC, val); + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + val = I915_READ(WM_MISC); + if (results->partitioning == INTEL_DDB_PART_1_2) + val &= ~WM_MISC_DATA_PARTITION_5_6; + else + val |= WM_MISC_DATA_PARTITION_5_6; + I915_WRITE(WM_MISC, val); + } else { + val = I915_READ(DISP_ARB_CTL2); + if (results->partitioning == INTEL_DDB_PART_1_2) + val &= ~DISP_DATA_PARTITION_5_6; + else + val |= DISP_DATA_PARTITION_5_6; + I915_WRITE(DISP_ARB_CTL2, val); + } } if (dirty & WM_DIRTY_FBC) { @@ -2905,37 +2501,48 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(DISP_ARB_CTL, val); } - if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) + if (dirty & WM_DIRTY_LP(1) && + previous->wm_lp_spr[0] != results->wm_lp_spr[0]) I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); - if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1]) - I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); - if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2]) - I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); - if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0) + if (INTEL_INFO(dev)->gen >= 7) { + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1]) + I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2]) + I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); + } + + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != results->wm_lp[0]) I915_WRITE(WM1_LP_ILK, results->wm_lp[0]); - if (dirty & WM_DIRTY_LP(2) && results->wm_lp[1] != 0) + if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != results->wm_lp[1]) I915_WRITE(WM2_LP_ILK, results->wm_lp[1]); - if (dirty & WM_DIRTY_LP(3) && results->wm_lp[2] != 0) + if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != results->wm_lp[2]) I915_WRITE(WM3_LP_ILK, results->wm_lp[2]); dev_priv->wm.hw = *results; } -static void haswell_update_wm(struct drm_crtc *crtc) +static bool ilk_disable_lp_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL); +} + +static void ilk_update_wm(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct hsw_wm_maximums max; - struct hsw_pipe_wm_parameters params = {}; - struct hsw_wm_values results = {}; + struct ilk_wm_maximums max; + struct ilk_pipe_wm_parameters params = {}; + struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; struct intel_pipe_wm pipe_wm = {}; struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct intel_wm_config config = {}; - hsw_compute_wm_parameters(crtc, ¶ms, &config); + ilk_compute_wm_parameters(crtc, ¶ms, &config); intel_compute_pipe_wm(crtc, ¶ms, &pipe_wm); @@ -2945,15 +2552,15 @@ static void haswell_update_wm(struct drm_crtc *crtc) intel_crtc->wm.active = pipe_wm; ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); - ilk_wm_merge(dev, &max, &lp_wm_1_2); + ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active == 1 && config.sprites_enabled) { ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); - ilk_wm_merge(dev, &max, &lp_wm_5_6); + ilk_wm_merge(dev, &config, &max, &lp_wm_5_6); - best_lp_wm = hsw_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); + best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { best_lp_wm = &lp_wm_1_2; } @@ -2961,16 +2568,17 @@ static void haswell_update_wm(struct drm_crtc *crtc) partitioning = (best_lp_wm == &lp_wm_1_2) ? INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6; - hsw_compute_wm_results(dev, best_lp_wm, partitioning, &results); + ilk_compute_wm_results(dev, best_lp_wm, partitioning, &results); - hsw_write_wm_values(dev_priv, &results); + ilk_write_wm_values(dev_priv, &results); } -static void haswell_update_sprite_wm(struct drm_plane *plane, +static void ilk_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t sprite_width, int pixel_size, bool enabled, bool scaled) { + struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); intel_plane->wm.enabled = enabled; @@ -2978,176 +2586,24 @@ static void haswell_update_sprite_wm(struct drm_plane *plane, intel_plane->wm.horiz_pixels = sprite_width; intel_plane->wm.bytes_per_pixel = pixel_size; - haswell_update_wm(crtc); -} - -static bool -sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int display_latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - int clock; - int entries, tlb_miss; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (!intel_crtc_active(crtc)) { - *sprite_wm = display->guard_size; - return false; - } - - clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - - /* Use the small buffer method to calculate the sprite watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; - tlb_miss = display->fifo_size*display->cacheline_size - - sprite_width * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = DIV_ROUND_UP(entries, display->cacheline_size); - *sprite_wm = entries + display->guard_size; - if (*sprite_wm > (int)display->max_wm) - *sprite_wm = display->max_wm; - - return true; -} - -static bool -sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - unsigned long line_time_us; - int clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *sprite_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - if (!clock) { - *sprite_wm = 0; - return false; - } - - line_time_us = (sprite_width * 1000) / clock; - if (!line_time_us) { - *sprite_wm = 0; - return false; - } - - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = sprite_width * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *sprite_wm = entries + display->guard_size; - - return *sprite_wm > 0x3ff ? false : true; -} - -static void sandybridge_update_sprite_wm(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, int pixel_size, - bool enabled, bool scaled) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe = to_intel_plane(plane)->pipe; - int latency = dev_priv->wm.spr_latency[0] * 100; /* In unit 0.1us */ - u32 val; - int sprite_wm, reg; - int ret; - - if (!enabled) - return; - - switch (pipe) { - case 0: - reg = WM0_PIPEA_ILK; - break; - case 1: - reg = WM0_PIPEB_ILK; - break; - case 2: - reg = WM0_PIPEC_IVB; - break; - default: - return; /* bad pipe */ - } - - ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, - &sandybridge_display_wm_info, - latency, &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n", - pipe_name(pipe)); - return; - } - - val = I915_READ(reg); - val &= ~WM0_PIPE_SPRITE_MASK; - I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); - DRM_DEBUG_KMS("sprite watermarks For pipe %c - %d\n", pipe_name(pipe), sprite_wm); - - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - dev_priv->wm.spr_latency[1] * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n", - pipe_name(pipe)); - return; - } - I915_WRITE(WM1S_LP_ILK, sprite_wm); - - /* Only IVB has two more LP watermarks for sprite */ - if (!IS_IVYBRIDGE(dev)) - return; - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - dev_priv->wm.spr_latency[2] * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n", - pipe_name(pipe)); - return; - } - I915_WRITE(WM2S_LP_IVB, sprite_wm); + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + * + * WaCxSRDisabledForSpriteScaling:ivb + */ + if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev)) + intel_wait_for_vblank(dev, intel_plane->pipe); - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - dev_priv->wm.spr_latency[3] * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n", - pipe_name(pipe)); - return; - } - I915_WRITE(WM3S_LP_IVB, sprite_wm); + ilk_update_wm(crtc); } static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct hsw_wm_values *hw = &dev_priv->wm.hw; + struct ilk_wm_values *hw = &dev_priv->wm.hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_pipe_wm *active = &intel_crtc->wm.active; enum pipe pipe = intel_crtc->pipe; @@ -3158,7 +2614,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) }; hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]); - hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe)); if (intel_crtc_active(crtc)) { u32 tmp = hw->wm_pipe[pipe]; @@ -3190,7 +2647,7 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) void ilk_wm_get_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct hsw_wm_values *hw = &dev_priv->wm.hw; + struct ilk_wm_values *hw = &dev_priv->wm.hw; struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) @@ -3204,8 +2661,12 @@ void ilk_wm_get_hw_state(struct drm_device *dev) hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); - hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? - INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? + INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; + else if (IS_IVYBRIDGE(dev)) + hw->partitioning = (I915_READ(DISP_ARB_CTL2) & DISP_DATA_PARTITION_5_6) ? + INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2; hw->enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); @@ -3430,26 +2891,19 @@ static void ironlake_disable_drps(struct drm_device *dev) * ourselves, instead of doing a rmw cycle (which might result in us clearing * all limits and the gpu stuck at whatever frequency it is at atm). */ -static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 *val) +static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val) { u32 limits; - limits = 0; - - if (*val >= dev_priv->rps.max_delay) - *val = dev_priv->rps.max_delay; - limits |= dev_priv->rps.max_delay << 24; - /* Only set the down limit when we've reached the lowest level to avoid * getting more interrupts, otherwise leave this clear. This prevents a * race in the hw when coming out of rc6: There's a tiny window where * the hw runs at the minimal clock before selecting the desired * frequency, if the down threshold expires in that window we will not * receive a down interrupt. */ - if (*val <= dev_priv->rps.min_delay) { - *val = dev_priv->rps.min_delay; + limits = dev_priv->rps.max_delay << 24; + if (val <= dev_priv->rps.min_delay) limits |= dev_priv->rps.min_delay << 16; - } return limits; } @@ -3549,7 +3003,6 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) void gen6_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits = gen6_rps_limits(dev_priv, &val); WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); @@ -3572,7 +3025,8 @@ void gen6_set_rps(struct drm_device *dev, u8 val) /* Make sure we continue to get interrupts * until we hit the minimum or maximum frequencies. */ - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + gen6_rps_limits(dev_priv, val)); POSTING_READ(GEN6_RPNSWREQ); @@ -3583,9 +3037,11 @@ void gen6_set_rps(struct drm_device *dev, u8 val) void gen6_rps_idle(struct drm_i915_private *dev_priv) { + struct drm_device *dev = dev_priv->dev; + mutex_lock(&dev_priv->rps.hw_lock); if (dev_priv->rps.enabled) { - if (dev_priv->info->is_valleyview) + if (IS_VALLEYVIEW(dev)) valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay); else gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay); @@ -3596,9 +3052,11 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv) void gen6_rps_boost(struct drm_i915_private *dev_priv) { + struct drm_device *dev = dev_priv->dev; + mutex_lock(&dev_priv->rps.hw_lock); if (dev_priv->rps.enabled) { - if (dev_priv->info->is_valleyview) + if (IS_VALLEYVIEW(dev)) valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay); else gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay); @@ -3607,48 +3065,18 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->rps.hw_lock); } -/* - * Wait until the previous freq change has completed, - * or the timeout elapsed, and then update our notion - * of the current GPU frequency. - */ -static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) -{ - u32 pval; - - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); - - if (wait_for(((pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS)) & GENFREQSTATUS) == 0, 10)) - DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); - - pval >>= 8; - - if (pval != dev_priv->rps.cur_delay) - DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay), - dev_priv->rps.cur_delay, - vlv_gpu_freq(dev_priv->mem_freq, pval), pval); - - dev_priv->rps.cur_delay = pval; -} - void valleyview_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - gen6_rps_limits(dev_priv, &val); - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); - vlv_update_rps_cur_delay(dev_priv); - DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.cur_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay, - vlv_gpu_freq(dev_priv->mem_freq, val), val); + vlv_gpu_freq(dev_priv, val), val); if (val == dev_priv->rps.cur_delay) return; @@ -3657,7 +3085,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) dev_priv->rps.cur_delay = val; - trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); + trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val)); } static void gen6_disable_rps_interrupts(struct drm_device *dev) @@ -3775,7 +3203,7 @@ static void gen8_enable_rps(struct drm_device *dev) /* 1c & 1d: Get forcewake during program sequence. Although the driver * hasn't enabled a state yet where we need forcewake, BIOS may have.*/ - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); /* 2a: Disable RC states. */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -3832,7 +3260,7 @@ static void gen8_enable_rps(struct drm_device *dev) gen6_enable_rps_interrupts(dev); - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } static void gen6_enable_rps(struct drm_device *dev) @@ -3862,7 +3290,7 @@ static void gen6_enable_rps(struct drm_device *dev) I915_WRITE(GTFIFODBG, gtfifodbg); } - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); @@ -3954,7 +3382,7 @@ static void gen6_enable_rps(struct drm_device *dev) DRM_ERROR("Couldn't fix incorrect rc6 voltage\n"); } - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } void gen6_update_ring_freq(struct drm_device *dev) @@ -4116,7 +3544,8 @@ static void valleyview_enable_rps(struct drm_device *dev) valleyview_setup_pctx(dev); - gen6_gt_force_wake_get(dev_priv); + /* If VLV, Forcewake all wells, else re-direct to regular path */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400); I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000); @@ -4140,7 +3569,7 @@ static void valleyview_enable_rps(struct drm_device *dev) for_each_ring(ring, dev_priv, i) I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); - I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350); + I915_WRITE(GEN6_RC6_THRESHOLD, 0x557); /* allows RC6 residency counter to work */ I915_WRITE(VLV_COUNTER_CONTROL, @@ -4148,65 +3577,47 @@ static void valleyview_enable_rps(struct drm_device *dev) VLV_MEDIA_RC6_COUNT_EN | VLV_RENDER_RC6_COUNT_EN)); if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE) - rc6_mode = GEN7_RC_CTL_TO_MODE; + rc6_mode = GEN7_RC_CTL_TO_MODE | VLV_RC_CTL_CTX_RST_PARALLEL; intel_print_rc6_info(dev, rc6_mode); I915_WRITE(GEN6_RC_CONTROL, rc6_mode); val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - switch ((val >> 6) & 3) { - case 0: - case 1: - dev_priv->mem_freq = 800; - break; - case 2: - dev_priv->mem_freq = 1066; - break; - case 3: - dev_priv->mem_freq = 1333; - break; - } - DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val); dev_priv->rps.cur_delay = (val >> 8) & 0xff; DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.cur_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay), dev_priv->rps.cur_delay); dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); dev_priv->rps.hw_max = dev_priv->rps.max_delay; DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.max_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay), dev_priv->rps.max_delay); dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv); DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.rpe_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay), dev_priv->rps.rpe_delay); dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv); DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.min_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay), dev_priv->rps.min_delay); DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.rpe_delay), + vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay), dev_priv->rps.rpe_delay); valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); gen6_enable_rps_interrupts(dev); - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } void ironlake_teardown_rc6(struct drm_device *dev) @@ -5019,6 +4430,20 @@ static void g4x_disable_trickle_feed(struct drm_device *dev) } } +static void ilk_init_lp_watermarks(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN); + I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN); + I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN); + + /* + * Don't touch WM1S_LP_EN here. + * Doing so could cause underruns. + */ +} + static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5052,9 +4477,8 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(DISP_ARB_CTL, (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + + ilk_init_lp_watermarks(dev); /* * Based on the document from hardware guys the following bits @@ -5161,9 +4585,7 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + ilk_init_lp_watermarks(dev); I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); @@ -5304,28 +4726,40 @@ 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) { struct drm_i915_private *dev_priv = dev->dev_private; - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + ilk_init_lp_watermarks(dev); /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. * This implements the WaDisableRCZUnitClockGating:hsw workaround. @@ -5374,9 +4808,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t snpcr; - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + ilk_init_lp_watermarks(dev); I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); @@ -5463,6 +4895,26 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) static void valleyview_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); + mutex_unlock(&dev_priv->rps.hw_lock); + switch ((val >> 6) & 3) { + case 0: + dev_priv->mem_freq = 800; + break; + case 1: + dev_priv->mem_freq = 1066; + break; + case 2: + dev_priv->mem_freq = 1333; + break; + case 3: + dev_priv->mem_freq = 1333; + break; + } + DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); @@ -5642,50 +5094,133 @@ void intel_suspend_hw(struct drm_device *dev) lpt_suspend_hw(dev); } -static bool is_always_on_power_domain(struct drm_device *dev, - enum intel_display_power_domain domain) -{ - unsigned long always_on_domains; +#define for_each_power_well(i, power_well, domain_mask, power_domains) \ + for (i = 0; \ + i < (power_domains)->power_well_count && \ + ((power_well) = &(power_domains)->power_wells[i]); \ + i++) \ + if ((power_well)->domains & (domain_mask)) - BUG_ON(BIT(domain) & ~POWER_DOMAIN_MASK); - - if (IS_BROADWELL(dev)) { - always_on_domains = BDW_ALWAYS_ON_POWER_DOMAINS; - } else if (IS_HASWELL(dev)) { - always_on_domains = HSW_ALWAYS_ON_POWER_DOMAINS; - } else { - WARN_ON(1); - return true; - } - - return BIT(domain) & always_on_domains; -} +#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \ + for (i = (power_domains)->power_well_count - 1; \ + i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\ + i--) \ + if ((power_well)->domains & (domain_mask)) /** * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to * be enabled. */ +static bool hsw_power_well_enabled(struct drm_device *dev, + struct i915_power_well *power_well) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(HSW_PWR_WELL_DRIVER) == + (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); +} + +bool intel_display_power_enabled_sw(struct drm_device *dev, + enum intel_display_power_domain domain) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_power_domains *power_domains; + + power_domains = &dev_priv->power_domains; + + return power_domains->domain_use_count[domain]; +} + bool intel_display_power_enabled(struct drm_device *dev, enum intel_display_power_domain domain) { struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_power_domains *power_domains; + struct i915_power_well *power_well; + bool is_enabled; + int i; - if (!HAS_POWER_WELL(dev)) - return true; + power_domains = &dev_priv->power_domains; - if (is_always_on_power_domain(dev, domain)) - return true; + is_enabled = true; - return I915_READ(HSW_PWR_WELL_DRIVER) == - (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); + mutex_lock(&power_domains->lock); + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { + if (power_well->always_on) + continue; + + if (!power_well->is_enabled(dev, power_well)) { + is_enabled = false; + break; + } + } + mutex_unlock(&power_domains->lock); + + 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 __intel_set_power_well(struct drm_device *dev, bool enable) +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); @@ -5706,42 +5241,14 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable) 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); } } } @@ -5751,9 +5258,9 @@ static void __intel_power_well_get(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; - if (!power_well->count++) { + if (!power_well->count++ && power_well->set) { hsw_disable_package_c8(dev_priv); - __intel_set_power_well(dev, true); + power_well->set(dev, power_well, true); } } @@ -5763,8 +5270,10 @@ static void __intel_power_well_put(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; WARN_ON(!power_well->count); - if (!--power_well->count && i915_disable_power_well) { - __intel_set_power_well(dev, false); + + if (!--power_well->count && power_well->set && + i915_disable_power_well) { + power_well->set(dev, power_well, false); hsw_enable_package_c8(dev_priv); } } @@ -5774,17 +5283,18 @@ void intel_display_power_get(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; - - if (!HAS_POWER_WELL(dev)) - return; - - if (is_always_on_power_domain(dev, domain)) - return; + struct i915_power_well *power_well; + int i; power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); - __intel_power_well_get(dev, &power_domains->power_wells[0]); + + for_each_power_well(i, power_well, BIT(domain), power_domains) + __intel_power_well_get(dev, power_well); + + power_domains->domain_use_count[domain]++; + mutex_unlock(&power_domains->lock); } @@ -5793,17 +5303,19 @@ void intel_display_power_put(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains; - - if (!HAS_POWER_WELL(dev)) - return; - - if (is_always_on_power_domain(dev, domain)) - return; + struct i915_power_well *power_well; + int i; power_domains = &dev_priv->power_domains; mutex_lock(&power_domains->lock); - __intel_power_well_put(dev, &power_domains->power_wells[0]); + + WARN_ON(!power_domains->domain_use_count[domain]); + power_domains->domain_use_count[domain]--; + + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) + __intel_power_well_put(dev, power_well); + mutex_unlock(&power_domains->lock); } @@ -5819,10 +5331,7 @@ void i915_request_power_well(void) dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); - - mutex_lock(&hsw_pwr->lock); - __intel_power_well_get(dev_priv->dev, &hsw_pwr->power_wells[0]); - mutex_unlock(&hsw_pwr->lock); + intel_display_power_get(dev_priv->dev, POWER_DOMAIN_AUDIO); } EXPORT_SYMBOL_GPL(i915_request_power_well); @@ -5836,24 +5345,71 @@ void i915_release_power_well(void) dev_priv = container_of(hsw_pwr, struct drm_i915_private, power_domains); - - mutex_lock(&hsw_pwr->lock); - __intel_power_well_put(dev_priv->dev, &hsw_pwr->power_wells[0]); - mutex_unlock(&hsw_pwr->lock); + intel_display_power_put(dev_priv->dev, POWER_DOMAIN_AUDIO); } EXPORT_SYMBOL_GPL(i915_release_power_well); +static struct i915_power_well i9xx_always_on_power_well[] = { + { + .name = "always-on", + .always_on = 1, + .domains = POWER_DOMAIN_MASK, + }, +}; + +static struct i915_power_well hsw_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = HSW_ALWAYS_ON_POWER_DOMAINS, + }, + { + .name = "display", + .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS, + .is_enabled = hsw_power_well_enabled, + .set = hsw_set_power_well, + }, +}; + +static struct i915_power_well bdw_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = BDW_ALWAYS_ON_POWER_DOMAINS, + }, + { + .name = "display", + .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS, + .is_enabled = hsw_power_well_enabled, + .set = hsw_set_power_well, + }, +}; + +#define set_power_wells(power_domains, __power_wells) ({ \ + (power_domains)->power_wells = (__power_wells); \ + (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \ +}) + int intel_power_domains_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; - struct i915_power_well *power_well; mutex_init(&power_domains->lock); - hsw_pwr = power_domains; - power_well = &power_domains->power_wells[0]; - power_well->count = 0; + /* + * The enabling order will be from lower to higher indexed wells, + * the disabling order is reversed. + */ + if (IS_HASWELL(dev)) { + set_power_wells(power_domains, hsw_power_wells); + hsw_pwr = power_domains; + } else if (IS_BROADWELL(dev)) { + set_power_wells(power_domains, bdw_power_wells); + hsw_pwr = power_domains; + } else { + set_power_wells(power_domains, i9xx_always_on_power_well); + } return 0; } @@ -5868,15 +5424,13 @@ static void intel_power_domains_resume(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *power_well; - - if (!HAS_POWER_WELL(dev)) - return; + int i; mutex_lock(&power_domains->lock); - - power_well = &power_domains->power_wells[0]; - __intel_set_power_well(dev, power_well->count > 0); - + for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { + if (power_well->set) + power_well->set(dev, power_well, power_well->count > 0); + } mutex_unlock(&power_domains->lock); } @@ -5890,13 +5444,13 @@ void intel_power_domains_init_hw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!HAS_POWER_WELL(dev)) - return; - /* For now, we need the power well to be always enabled. */ intel_display_set_init_power(dev, true); intel_power_domains_resume(dev); + if (!(IS_HASWELL(dev) || IS_BROADWELL(dev))) + return; + /* We're taking over the BIOS, so clear any requests made by it since * the driver is in charge now. */ if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST) @@ -5914,31 +5468,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 (HAS_FBC(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 */ @@ -5951,58 +5560,27 @@ void intel_init_pm(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { intel_setup_wm_latency(dev); - if (IS_GEN5(dev)) { - if (dev_priv->wm.pri_latency[1] && - dev_priv->wm.spr_latency[1] && - dev_priv->wm.cur_latency[1]) - dev_priv->display.update_wm = ironlake_update_wm; - else { - DRM_DEBUG_KMS("Failed to get proper latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } + if ((IS_GEN5(dev) && dev_priv->wm.pri_latency[1] && + dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) || + (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] && + dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { + dev_priv->display.update_wm = ilk_update_wm; + dev_priv->display.update_sprite_wm = ilk_update_sprite_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + } + + if (IS_GEN5(dev)) dev_priv->display.init_clock_gating = ironlake_init_clock_gating; - } else if (IS_GEN6(dev)) { - if (dev_priv->wm.pri_latency[0] && - dev_priv->wm.spr_latency[0] && - dev_priv->wm.cur_latency[0]) { - dev_priv->display.update_wm = sandybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } + else if (IS_GEN6(dev)) dev_priv->display.init_clock_gating = gen6_init_clock_gating; - } else if (IS_IVYBRIDGE(dev)) { - if (dev_priv->wm.pri_latency[0] && - dev_priv->wm.spr_latency[0] && - dev_priv->wm.cur_latency[0]) { - dev_priv->display.update_wm = ivybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } + else if (IS_IVYBRIDGE(dev)) dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; - } else if (IS_HASWELL(dev)) { - if (dev_priv->wm.pri_latency[0] && - dev_priv->wm.spr_latency[0] && - dev_priv->wm.cur_latency[0]) { - dev_priv->display.update_wm = haswell_update_wm; - dev_priv->display.update_sprite_wm = - haswell_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } + else if (IS_HASWELL(dev)) dev_priv->display.init_clock_gating = haswell_init_clock_gating; - } else if (INTEL_INFO(dev)->gen == 8) { + else if (INTEL_INFO(dev)->gen == 8) dev_priv->display.init_clock_gating = gen8_init_clock_gating; - } else - dev_priv->display.update_wm = NULL; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.update_wm = valleyview_update_wm; dev_priv->display.init_clock_gating = @@ -6036,21 +5614,21 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; dev_priv->display.init_clock_gating = gen3_init_clock_gating; - } else if (IS_I865G(dev)) { - dev_priv->display.update_wm = i830_update_wm; - dev_priv->display.init_clock_gating = i85x_init_clock_gating; - dev_priv->display.get_fifo_size = i830_get_fifo_size; - } else if (IS_I85X(dev)) { - dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i85x_get_fifo_size; - dev_priv->display.init_clock_gating = i85x_init_clock_gating; - } else { - dev_priv->display.update_wm = i830_update_wm; - dev_priv->display.init_clock_gating = i830_init_clock_gating; - if (IS_845G(dev)) + } else if (IS_GEN2(dev)) { + if (INTEL_INFO(dev)->num_pipes == 1) { + dev_priv->display.update_wm = i845_update_wm; dev_priv->display.get_fifo_size = i845_get_fifo_size; - else + } else { + dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i830_get_fifo_size; + } + + if (IS_I85X(dev) || IS_I865G(dev)) + dev_priv->display.init_clock_gating = i85x_init_clock_gating; + else + dev_priv->display.init_clock_gating = i830_init_clock_gating; + } else { + DRM_ERROR("unexpected fall-through in intel_init_pm\n"); } } @@ -6101,59 +5679,48 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) return 0; } -int vlv_gpu_freq(int ddr_freq, int val) +int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val) { - int mult, base; + int div; - switch (ddr_freq) { + /* 4 x czclk */ + switch (dev_priv->mem_freq) { case 800: - mult = 20; - base = 120; + div = 10; break; case 1066: - mult = 22; - base = 133; + div = 12; break; case 1333: - mult = 21; - base = 125; + div = 16; break; default: return -1; } - return ((val - 0xbd) * mult) + base; + return DIV_ROUND_CLOSEST(dev_priv->mem_freq * (val + 6 - 0xbd), 4 * div); } -int vlv_freq_opcode(int ddr_freq, int val) +int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val) { - int mult, base; + int mul; - switch (ddr_freq) { + /* 4 x czclk */ + switch (dev_priv->mem_freq) { case 800: - mult = 20; - base = 120; + mul = 10; break; case 1066: - mult = 22; - base = 133; + mul = 12; break; case 1333: - mult = 21; - base = 125; + mul = 16; break; default: return -1; } - val /= mult; - val -= base / mult; - val += 0xbd; - - if (val > 0xea) - val = 0xea; - - return val; + return DIV_ROUND_CLOSEST(4 * mul * val, dev_priv->mem_freq) + 0xbd - 6; } void intel_pm_setup(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c2f09d456300..8fcb32a02cb4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -285,14 +285,16 @@ static int gen7_ring_fbc_flush(struct intel_ring_buffer *ring, u32 value) if (!ring->fbc_dirty) return 0; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(ring, 6); if (ret) return ret; - intel_ring_emit(ring, MI_NOOP); /* WaFbcNukeOn3DBlt:ivb/hsw */ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(ring, MSG_FBC_REND_STATE); intel_ring_emit(ring, value); + intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | MI_SRM_LRM_GLOBAL_GTT); + intel_ring_emit(ring, MSG_FBC_REND_STATE); + intel_ring_emit(ring, ring->scratch.gtt_offset + 256); intel_ring_advance(ring); ring->fbc_dirty = false; @@ -354,7 +356,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, 0); intel_ring_advance(ring); - if (flush_domains) + if (!invalidate_domains && flush_domains) return gen7_ring_fbc_flush(ring, FBC_REND_NUKE); return 0; @@ -436,7 +438,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) int ret = 0; u32 head; - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); if (I915_NEED_GFX_HWS(dev)) intel_ring_setup_status_page(ring); @@ -509,7 +511,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); out: - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); return ret; } @@ -661,14 +663,15 @@ gen6_add_request(struct intel_ring_buffer *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *useless; - int i, ret; + int i, ret, num_dwords = 4; - ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) * - MBOX_UPDATE_DWORDS) + - 4); + if (i915_semaphore_is_enabled(dev)) + num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS); +#undef MBOX_UPDATE_DWORDS + + ret = intel_ring_begin(ring, num_dwords); if (ret) return ret; -#undef MBOX_UPDATE_DWORDS for_each_ring(useless, dev_priv, i) { u32 mbox_reg = ring->signal_mbox[i]; @@ -1030,11 +1033,6 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) if (!dev->irq_enabled) return false; - /* It looks like we need to prevent the gt from suspending while waiting - * for an notifiy irq, otherwise irqs seem to get lost on at least the - * blt/bsd rings on ivb. */ - gen6_gt_force_wake_get(dev_priv); - spin_lock_irqsave(&dev_priv->irq_lock, flags); if (ring->irq_refcount++ == 0) { if (HAS_L3_DPF(dev) && ring->id == RCS) @@ -1066,8 +1064,6 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) ilk_disable_gt_irq(dev_priv, ring->irq_enable_mask); } spin_unlock_irqrestore(&dev_priv->irq_lock, flags); - - gen6_gt_force_wake_put(dev_priv); } static bool @@ -1611,8 +1607,8 @@ intel_ring_alloc_seqno(struct intel_ring_buffer *ring) return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); } -static int __intel_ring_begin(struct intel_ring_buffer *ring, - int bytes) +static int __intel_ring_prepare(struct intel_ring_buffer *ring, + int bytes) { int ret; @@ -1628,7 +1624,6 @@ static int __intel_ring_begin(struct intel_ring_buffer *ring, return ret; } - ring->space -= bytes; return 0; } @@ -1643,12 +1638,17 @@ int intel_ring_begin(struct intel_ring_buffer *ring, if (ret) return ret; + ret = __intel_ring_prepare(ring, num_dwords * sizeof(uint32_t)); + if (ret) + return ret; + /* Preallocate the olr before touching the ring */ ret = intel_ring_alloc_seqno(ring); if (ret) return ret; - return __intel_ring_begin(ring, num_dwords * sizeof(uint32_t)); + ring->space -= num_dwords * sizeof(uint32_t); + return 0; } void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno) @@ -1838,7 +1838,7 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, } intel_ring_advance(ring); - if (IS_GEN7(dev) && flush) + if (IS_GEN7(dev) && !invalidate && flush) return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN); return 0; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a583e8f718a7..95bdfb3c431c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -413,23 +413,34 @@ static const struct _sdvo_cmd_name { static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) { - int i; + int i, pos = 0; +#define BUF_LEN 256 + char buffer[BUF_LEN]; + +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args) + - DRM_DEBUG_KMS("%s: W: %02X ", - SDVO_NAME(intel_sdvo), cmd); - for (i = 0; i < args_len; i++) - DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); - for (; i < 8; i++) - DRM_LOG_KMS(" "); + for (i = 0; i < args_len; i++) { + BUF_PRINT("%02X ", ((u8 *)args)[i]); + } + for (; i < 8; i++) { + BUF_PRINT(" "); + } for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); + BUF_PRINT("(%s)", sdvo_cmd_names[i].name); break; } } - if (i == ARRAY_SIZE(sdvo_cmd_names)) - DRM_LOG_KMS("(%02X)", cmd); - DRM_LOG_KMS("\n"); + if (i == ARRAY_SIZE(sdvo_cmd_names)) { + BUF_PRINT("(%02X)", cmd); + } + BUG_ON(pos >= BUF_LEN - 1); +#undef BUF_PRINT +#undef BUF_LEN + + DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer); } static const char *cmd_status_names[] = { @@ -512,9 +523,10 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, { u8 retry = 15; /* 5 quick checks, followed by 10 long checks */ u8 status; - int i; + int i, pos = 0; +#define BUF_LEN 256 + char buffer[BUF_LEN]; - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); /* * The documentation states that all commands will be @@ -551,10 +563,13 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, goto log_fail; } +#define BUF_PRINT(args...) \ + pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args) + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - DRM_LOG_KMS("(%s)", cmd_status_names[status]); + BUF_PRINT("(%s)", cmd_status_names[status]); else - DRM_LOG_KMS("(??? %d)", status); + BUF_PRINT("(??? %d)", status); if (status != SDVO_CMD_STATUS_SUCCESS) goto log_fail; @@ -565,13 +580,17 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); + BUF_PRINT(" %02X", ((u8 *)response)[i]); } - DRM_LOG_KMS("\n"); + BUG_ON(pos >= BUF_LEN - 1); +#undef BUF_PRINT +#undef BUF_LEN + + DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer); return true; log_fail: - DRM_LOG_KMS("... failed\n"); + DRM_DEBUG_KMS("%s: R: ... failed\n", SDVO_NAME(intel_sdvo)); return false; } @@ -933,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]; @@ -1517,8 +1536,9 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) intel_modeset_check_state(connector->dev); } -static int intel_sdvo_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status +intel_sdvo_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 770bdd6ecd9f..2e2d4eb4a00d 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 9944d8135e87..0954f132726e 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -90,6 +90,22 @@ void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) mutex_unlock(&dev_priv->dpio_lock); } +u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT, + PUNIT_OPCODE_REG_READ, reg, &val); + + return val; +} + +void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT, + PUNIT_OPCODE_REG_WRITE, reg, &val); +} + u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr) { u32 val = 0; @@ -160,27 +176,18 @@ void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) PUNIT_OPCODE_REG_WRITE, reg, &val); } -static u32 vlv_get_phy_port(enum pipe pipe) -{ - u32 port = IOSF_PORT_DPIO; - - WARN_ON ((pipe != PIPE_A) && (pipe != PIPE_B)); - - return port; -} - u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = 0; - vlv_sideband_rw(dev_priv, DPIO_DEVFN, vlv_get_phy_port(pipe), + vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), DPIO_OPCODE_REG_READ, reg, &val); return val; } void vlv_dpio_write(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 val) { - vlv_sideband_rw(dev_priv, DPIO_DEVFN, vlv_get_phy_port(pipe), + vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)), DPIO_OPCODE_REG_WRITE, reg, &val); } @@ -242,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_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b9fabf826f7d..fe4de89c374c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -104,6 +104,12 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, break; } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + sprctl |= SP_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SP_TILED; @@ -224,7 +230,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; sprctl = I915_READ(SPRCTL(pipe)); @@ -257,6 +262,12 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, BUG(); } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + sprctl |= SPRITE_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SPRITE_TILED; @@ -279,21 +290,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, crtc_w--; crtc_h--; - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - */ - if (crtc_w != src_w || crtc_h != src_h) { - dev_priv->sprite_scaling_enabled |= 1 << pipe; - - if (!scaling_was_enabled) { - intel_update_watermarks(crtc); - intel_wait_for_vblank(dev, pipe); - } + if (crtc_w != src_w || crtc_h != src_h) sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - } else - dev_priv->sprite_scaling_enabled &= ~(1 << pipe); I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); @@ -320,10 +318,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, I915_MODIFY_DISPBASE(SPRSURF(pipe), i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); - - /* potentially re-enable LP watermarks */ - if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) - intel_update_watermarks(crtc); } static void @@ -333,7 +327,6 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; - bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ @@ -343,13 +336,13 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); - dev_priv->sprite_scaling_enabled &= ~(1 << pipe); + /* + * Avoid underruns when disabling the sprite. + * FIXME remove once watermark updates are done properly. + */ + intel_wait_for_vblank(dev, pipe); intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); - - /* potentially re-enable LP watermarks */ - if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) - intel_update_watermarks(crtc); } static int @@ -453,6 +446,12 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, BUG(); } + /* + * Enable gamma to match primary/cursor plane behaviour. + * FIXME should be user controllable via propertiesa. + */ + dvscntr |= DVS_GAMMA_ENABLE; + if (obj->tiling_mode != I915_TILING_NONE) dvscntr |= DVS_TILED; @@ -470,7 +469,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, crtc_h--; dvsscale = 0; - if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) + if (crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); @@ -510,6 +509,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); POSTING_READ(DVSSURF(pipe)); + /* + * Avoid underruns when disabling the sprite. + * FIXME remove once watermark updates are done properly. + */ + intel_wait_for_vblank(dev, pipe); + intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false); } @@ -643,6 +648,15 @@ format_is_yuv(uint32_t format) } } +static bool colorkey_enabled(struct intel_plane *intel_plane) +{ + struct drm_intel_sprite_colorkey key; + + intel_plane->get_colorkey(&intel_plane->base, &key); + + return key.flags != I915_SET_COLORKEY_NONE; +} + static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -828,7 +842,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ - disable_primary = drm_rect_equals(&dst, &clip); + disable_primary = drm_rect_equals(&dst, &clip) && !colorkey_enabled(intel_plane); WARN_ON(disable_primary && !visible && intel_crtc->active); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 25cbe073c388..2c8143c37de3 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -64,7 +64,8 @@ static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, ECOBUS); } -static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, + int fw_engine) { if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) @@ -89,7 +90,8 @@ static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, ECOBUS); } -static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv, + int fw_engine) { u32 forcewake_ack; @@ -121,12 +123,12 @@ static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv) u32 gtfifodbg; gtfifodbg = __raw_i915_read32(dev_priv, GTFIFODBG); - if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK, - "MMIO read or write has been dropped %x\n", gtfifodbg)) - __raw_i915_write32(dev_priv, GTFIFODBG, GT_FIFO_CPU_ERROR_MASK); + if (WARN(gtfifodbg, "GT wake FIFO error 0x%x\n", gtfifodbg)) + __raw_i915_write32(dev_priv, GTFIFODBG, gtfifodbg); } -static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, + int fw_engine) { __raw_i915_write32(dev_priv, FORCEWAKE, 0); /* something from same cacheline, but !FORCEWAKE */ @@ -134,7 +136,8 @@ static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) gen6_gt_check_fifodbg(dev_priv); } -static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) +static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv, + int fw_engine) { __raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); @@ -147,12 +150,19 @@ 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, GT_FIFO_FREE_ENTRIES); + u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) { udelay(10); - fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES); + fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; } if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES)) ++ret; @@ -171,38 +181,112 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV); } -static void vlv_force_wake_get(struct drm_i915_private *dev_priv) +static void __vlv_force_wake_get(struct drm_i915_private *dev_priv, + int fw_engine) { - if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, - FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); + /* Check for Render Engine */ + if (FORCEWAKE_RENDER & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_VLV) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Render forcewake old ack to clear.\n"); - __raw_i915_write32(dev_priv, FORCEWAKE_VLV, - _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); - __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, - _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + __raw_i915_write32(dev_priv, FORCEWAKE_VLV, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); - if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), - FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_VLV) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for Render to ack.\n"); + } - if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_MEDIA_VLV) & - FORCEWAKE_KERNEL), - FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); + /* Check for Media Engine */ + if (FORCEWAKE_MEDIA & fw_engine) { + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL) == 0, + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: Media forcewake old ack to clear.\n"); + + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + + if (wait_for_atomic((__raw_i915_read32(dev_priv, + FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out: waiting for media to ack.\n"); + } /* WaRsForcewakeWaitTC0:vlv */ __gen6_gt_wait_for_thread_c0(dev_priv); + } -static void vlv_force_wake_put(struct drm_i915_private *dev_priv) +static void __vlv_force_wake_put(struct drm_i915_private *dev_priv, + int fw_engine) { - __raw_i915_write32(dev_priv, FORCEWAKE_VLV, - _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); - __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, - _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + + /* Check for Render Engine */ + if (FORCEWAKE_RENDER & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_VLV, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + + + /* Check for Media Engine */ + if (FORCEWAKE_MEDIA & fw_engine) + __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + /* The below doubles as a POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); + +} + +void vlv_force_wake_get(struct drm_i915_private *dev_priv, + int fw_engine) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + if (FORCEWAKE_RENDER & fw_engine) { + if (dev_priv->uncore.fw_rendercount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_RENDER); + } + if (FORCEWAKE_MEDIA & fw_engine) { + if (dev_priv->uncore.fw_mediacount++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, + FORCEWAKE_MEDIA); + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +void vlv_force_wake_put(struct drm_i915_private *dev_priv, + int fw_engine) +{ + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + if (FORCEWAKE_RENDER & fw_engine) { + WARN_ON(dev_priv->uncore.fw_rendercount == 0); + if (--dev_priv->uncore.fw_rendercount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_RENDER); + } + + if (FORCEWAKE_MEDIA & fw_engine) { + WARN_ON(dev_priv->uncore.fw_mediacount == 0); + if (--dev_priv->uncore.fw_mediacount == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, + FORCEWAKE_MEDIA); + } + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void gen6_force_wake_work(struct work_struct *work) @@ -213,7 +297,7 @@ static void gen6_force_wake_work(struct work_struct *work) spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) - dev_priv->uncore.funcs.force_wake_put(dev_priv); + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } @@ -248,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); } @@ -256,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); @@ -281,29 +368,40 @@ void intel_uncore_sanitize(struct drm_device *dev) * be called at the beginning of the sequence followed by a call to * gen6_gt_force_wake_put() at the end of the sequence. */ -void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; 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); + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (dev_priv->uncore.forcewake_count++ == 0) - dev_priv->uncore.funcs.force_wake_get(dev_priv); + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } /* * see gen6_gt_force_wake_get() */ -void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) { unsigned long irqflags; if (!dev_priv->uncore.funcs.force_wake_put) return; + /* Redirect to VLV specific routine */ + if (IS_VALLEYVIEW(dev_priv->dev)) + return vlv_force_wake_put(dev_priv, fw_engine); + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); if (--dev_priv->uncore.forcewake_count == 0) { dev_priv->uncore.forcewake_count++; @@ -312,6 +410,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) 1); } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_runtime_pm_put(dev_priv); } /* We give fast paths for the really cool registers */ @@ -346,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; \ @@ -379,16 +486,51 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ REG_READ_HEADER(x); \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ if (dev_priv->uncore.forcewake_count == 0) \ - dev_priv->uncore.funcs.force_wake_get(dev_priv); \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, \ + FORCEWAKE_ALL); \ val = __raw_i915_read##x(dev_priv, reg); \ if (dev_priv->uncore.forcewake_count == 0) \ - dev_priv->uncore.funcs.force_wake_put(dev_priv); \ + dev_priv->uncore.funcs.force_wake_put(dev_priv, \ + FORCEWAKE_ALL); \ } else { \ val = __raw_i915_read##x(dev_priv, reg); \ } \ REG_READ_FOOTER; \ } +#define __vlv_read(x) \ +static u##x \ +vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ + unsigned fwengine = 0; \ + unsigned *fwcount; \ + REG_READ_HEADER(x); \ + if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \ + fwengine = FORCEWAKE_RENDER; \ + fwcount = &dev_priv->uncore.fw_rendercount; \ + } \ + else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \ + fwengine = FORCEWAKE_MEDIA; \ + fwcount = &dev_priv->uncore.fw_mediacount; \ + } \ + if (fwengine != 0) { \ + if ((*fwcount)++ == 0) \ + (dev_priv)->uncore.funcs.force_wake_get(dev_priv, \ + fwengine); \ + val = __raw_i915_read##x(dev_priv, reg); \ + if (--(*fwcount) == 0) \ + (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \ + fwengine); \ + } else { \ + val = __raw_i915_read##x(dev_priv, reg); \ + } \ + REG_READ_FOOTER; \ +} + + +__vlv_read(8) +__vlv_read(16) +__vlv_read(32) +__vlv_read(64) __gen6_read(8) __gen6_read(16) __gen6_read(32) @@ -402,6 +544,7 @@ __gen4_read(16) __gen4_read(32) __gen4_read(64) +#undef __vlv_read #undef __gen6_read #undef __gen5_read #undef __gen4_read @@ -413,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) \ @@ -427,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) \ @@ -438,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) \ @@ -453,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[] = { @@ -486,16 +634,18 @@ 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); \ + dev_priv->uncore.funcs.force_wake_get(dev_priv, \ + FORCEWAKE_ALL); \ } \ __raw_i915_write##x(dev_priv, reg, val); \ if (__needs_put) { \ - dev_priv->uncore.funcs.force_wake_put(dev_priv); \ + 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) @@ -524,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) @@ -534,8 +685,8 @@ void intel_uncore_init(struct drm_device *dev) gen6_force_wake_work); if (IS_VALLEYVIEW(dev)) { - dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; - dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; + dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get; + dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put; } else if (IS_HASWELL(dev) || IS_GEN8(dev)) { dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; @@ -552,9 +703,9 @@ void intel_uncore_init(struct drm_device *dev) * forcewake being disabled. */ mutex_lock(&dev->struct_mutex); - __gen6_gt_force_wake_mt_get(dev_priv); + __gen6_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL); ecobus = __raw_i915_read32(dev_priv, ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv); + __gen6_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev->struct_mutex); if (ecobus & FORCEWAKE_MT_ENABLE) { @@ -601,10 +752,18 @@ void intel_uncore_init(struct drm_device *dev) dev_priv->uncore.funcs.mmio_writel = gen6_write32; dev_priv->uncore.funcs.mmio_writeq = gen6_write64; } - dev_priv->uncore.funcs.mmio_readb = gen6_read8; - dev_priv->uncore.funcs.mmio_readw = gen6_read16; - dev_priv->uncore.funcs.mmio_readl = gen6_read32; - dev_priv->uncore.funcs.mmio_readq = gen6_read64; + + if (IS_VALLEYVIEW(dev)) { + dev_priv->uncore.funcs.mmio_readb = vlv_read8; + dev_priv->uncore.funcs.mmio_readw = vlv_read16; + dev_priv->uncore.funcs.mmio_readl = vlv_read32; + dev_priv->uncore.funcs.mmio_readq = vlv_read64; + } else { + dev_priv->uncore.funcs.mmio_readb = gen6_read8; + dev_priv->uncore.funcs.mmio_readw = gen6_read16; + dev_priv->uncore.funcs.mmio_readl = gen6_read32; + dev_priv->uncore.funcs.mmio_readq = gen6_read64; + } break; case 5: dev_priv->uncore.funcs.mmio_writeb = gen5_write8; @@ -687,6 +846,43 @@ int i915_reg_read_ioctl(struct drm_device *dev, return 0; } +int i915_get_reset_stats_ioctl(struct drm_device *dev, + void *data, struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_reset_stats *args = data; + struct i915_ctx_hang_stats *hs; + int ret; + + if (args->flags || args->pad) + return -EINVAL; + + if (args->ctx_id == DEFAULT_CONTEXT_ID && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id); + if (IS_ERR(hs)) { + mutex_unlock(&dev->struct_mutex); + return PTR_ERR(hs); + } + + if (capable(CAP_SYS_ADMIN)) + args->reset_count = i915_reset_count(&dev_priv->gpu_error); + else + args->reset_count = 0; + + args->batch_active = hs->batch_active; + args->batch_pending = hs->batch_pending; + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i965_reset_complete(struct drm_device *dev) { u8 gdrst; @@ -770,12 +966,12 @@ static int gen6_do_reset(struct drm_device *dev) /* If reset with a user forcewake, try to restore, otherwise turn it off */ if (dev_priv->uncore.forcewake_count) - dev_priv->uncore.funcs.force_wake_get(dev_priv); + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); else - dev_priv->uncore.funcs.force_wake_put(dev_priv); + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); /* Restore fifo count */ - dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES); + dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); return ret; @@ -793,15 +989,6 @@ int intel_gpu_reset(struct drm_device *dev) } } -void intel_uncore_clear_errors(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* XXX needs spinlock around caller's grouping */ - if (HAS_FPGA_DBG_UNCLAIMED(dev)) - __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); -} - void intel_uncore_check_errors(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 3a4e97bd8607..52aed893710a 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -222,6 +222,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_GEM_SET_CACHING 0x2f #define DRM_I915_GEM_GET_CACHING 0x30 #define DRM_I915_REG_READ 0x31 +#define DRM_I915_GET_RESET_STATS 0x32 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -271,6 +272,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) #define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) +#define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -1030,4 +1032,21 @@ struct drm_i915_reg_read { __u64 offset; __u64 val; /* Return value */ }; + +struct drm_i915_reset_stats { + __u32 ctx_id; + __u32 flags; + + /* All resets since boot/module reload, for all contexts */ + __u32 reset_count; + + /* Number of batches lost when active in GPU, for this context */ + __u32 batch_active; + + /* Number of batches lost pending for execution, for this context */ + __u32 batch_pending; + + __u32 pad; +}; + #endif /* _UAPI_I915_DRM_H_ */ |