diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-03 02:40:34 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-03 02:40:34 (GMT) |
commit | 20a2078ce7705a6e0722ef5184336eb8657a58d8 (patch) | |
tree | 5b927c96516380aa0ecd68d8a609f7cd72120ad5 /drivers/gpu/drm/i915 | |
parent | 0279b3c0ada1d78882f24acf94ac4595bd657a89 (diff) | |
parent | 307b9c022720f9de90d58e51743e01e9a42aec59 (diff) | |
download | linux-fsl-qoriq-20a2078ce7705a6e0722ef5184336eb8657a58d8.tar.xz |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"This is the main drm pull request for 3.10.
Wierd bits:
- OMAP drm changes required OMAP dss changes, in drivers/video, so I
took them in here.
- one more fbcon fix for font handover
- VT switch avoidance in pm code
- scatterlist helpers for gpu drivers - have acks from akpm
Highlights:
- qxl kms driver - driver for the spice qxl virtual GPU
Nouveau:
- fermi/kepler VRAM compression
- GK110/nvf0 modesetting support.
Tegra:
- host1x core merged with 2D engine support
i915:
- vt switchless resume
- more valleyview support
- vblank fixes
- modesetting pipe config rework
radeon:
- UVD engine support
- SI chip tiling support
- GPU registers initialisation from golden values.
exynos:
- device tree changes
- fimc block support
Otherwise:
- bunches of fixes all over the place."
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (513 commits)
qxl: update to new idr interfaces.
drm/nouveau: fix build with nv50->nvc0
drm/radeon: fix handling of v6 power tables
drm/radeon: clarify family checks in pm table parsing
drm/radeon: consolidate UVD clock programming
drm/radeon: fix UPLL_REF_DIV_MASK definition
radeon: add bo tracking debugfs
drm/radeon: add new richland pci ids
drm/radeon: add some new SI PCI ids
drm/radeon: fix scratch reg handling for UVD fence
drm/radeon: allocate SA bo in the requested domain
drm/radeon: fix possible segfault when parsing pm tables
drm/radeon: fix endian bugs in atom_allocate_fb_scratch()
OMAPDSS: TFP410: return EPROBE_DEFER if the i2c adapter not found
OMAPDSS: VENC: Add error handling for venc_probe_pdata
OMAPDSS: HDMI: Add error handling for hdmi_probe_pdata
OMAPDSS: RFBI: Add error handling for rfbi_probe_pdata
OMAPDSS: DSI: Add error handling for dsi_probe_pdata
OMAPDSS: SDI: Add error handling for sdi_probe_pdata
OMAPDSS: DPI: Add error handling for dpi_probe_pdata
...
Diffstat (limited to 'drivers/gpu/drm/i915')
32 files changed, 3397 insertions, 2221 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7299ea4..e913d32 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -772,6 +772,23 @@ static int i915_error_state(struct seq_file *m, void *unused) } } } + + obj = error->ring[i].ctx; + if (obj) { + seq_printf(m, "%s --- HW Context = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { + seq_printf(m, "[%04x] %08x %08x %08x %08x\n", + offset, + obj->pages[0][elt], + obj->pages[0][elt+1], + obj->pages[0][elt+2], + obj->pages[0][elt+3]); + offset += 16; + } + } } if (error->overlay) @@ -849,76 +866,42 @@ static const struct file_operations i915_error_state_fops = { .release = i915_error_state_release, }; -static ssize_t -i915_next_seqno_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_next_seqno_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - len = snprintf(buf, sizeof(buf), - "next_seqno : 0x%x\n", - dev_priv->next_seqno); - + *val = dev_priv->next_seqno; mutex_unlock(&dev->struct_mutex); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_next_seqno_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) -{ - struct drm_device *dev = filp->private_data; - char buf[20]; - u32 val = 1; +static int +i915_next_seqno_set(void *data, u64 val) +{ + struct drm_device *dev = data; int ret; - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - ret = kstrtouint(buf, 0, &val); - if (ret < 0) - return ret; - } - ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; ret = i915_gem_set_seqno(dev, val); - mutex_unlock(&dev->struct_mutex); - return ret ?: cnt; + return ret; } -static const struct file_operations i915_next_seqno_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_next_seqno_read, - .write = i915_next_seqno_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops, + i915_next_seqno_get, i915_next_seqno_set, + "0x%llx\n"); static int i915_rstdby_delays(struct seq_file *m, void *unused) { @@ -1023,6 +1006,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) max_freq = rp_state_cap & 0xff; seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", max_freq * GT_FREQUENCY_MULTIPLIER); + + seq_printf(m, "Max overclocked frequency: %dMHz\n", + dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER); } else { seq_printf(m, "no P-state info available\n"); } @@ -1371,7 +1357,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) return ret; - seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n"); + seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); for (gpu_freq = dev_priv->rps.min_delay; gpu_freq <= dev_priv->rps.max_delay; @@ -1380,7 +1366,10 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_MIN_FREQ_TABLE, &ia_freq); - seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100); + seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", + gpu_freq * GT_FREQUENCY_MULTIPLIER, + ((ia_freq >> 0) & 0xff) * 100, + ((ia_freq >> 8) & 0xff) * 100); } mutex_unlock(&dev_priv->rps.hw_lock); @@ -1680,105 +1669,51 @@ static int i915_dpio_info(struct seq_file *m, void *data) return 0; } -static ssize_t -i915_wedged_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_wedged_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len; - len = snprintf(buf, sizeof(buf), - "wedged : %d\n", - atomic_read(&dev_priv->gpu_error.reset_counter)); + *val = atomic_read(&dev_priv->gpu_error.reset_counter); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_wedged_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_wedged_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; - char buf[20]; - int val = 1; - - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; + struct drm_device *dev = data; - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } - - DRM_INFO("Manually setting wedged to %d\n", val); + DRM_INFO("Manually setting wedged to %llu\n", val); i915_handle_error(dev, val); - return cnt; + return 0; } -static const struct file_operations i915_wedged_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_wedged_read, - .write = i915_wedged_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops, + i915_wedged_get, i915_wedged_set, + "%llu\n"); -static ssize_t -i915_ring_stop_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_ring_stop_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[20]; - int len; - len = snprintf(buf, sizeof(buf), - "0x%08x\n", dev_priv->gpu_error.stop_rings); + *val = dev_priv->gpu_error.stop_rings; - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_ring_stop_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_ring_stop_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 0, ret; - - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } + int ret; - DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val); + DRM_DEBUG_DRIVER("Stopping rings 0x%08llx\n", val); ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -1787,16 +1722,12 @@ i915_ring_stop_write(struct file *filp, dev_priv->gpu_error.stop_rings = val; mutex_unlock(&dev->struct_mutex); - return cnt; + return 0; } -static const struct file_operations i915_ring_stop_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_ring_stop_read, - .write = i915_ring_stop_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_ring_stop_fops, + i915_ring_stop_get, i915_ring_stop_set, + "0x%08llx\n"); #define DROP_UNBOUND 0x1 #define DROP_BOUND 0x2 @@ -1806,46 +1737,23 @@ static const struct file_operations i915_ring_stop_fops = { DROP_BOUND | \ DROP_RETIRE | \ DROP_ACTIVE) -static ssize_t -i915_drop_caches_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_drop_caches_get(void *data, u64 *val) { - char buf[20]; - int len; + *val = DROP_ALL; - len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_drop_caches_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_drop_caches_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj, *next; - char buf[20]; - int val = 0, ret; - - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } + int ret; - DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val); + DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val); /* No need to check and wait for gpu resets, only libdrm auto-restarts * on ioctls on -EAGAIN. */ @@ -1883,27 +1791,19 @@ i915_drop_caches_write(struct file *filp, unlock: mutex_unlock(&dev->struct_mutex); - return ret ?: cnt; + return ret; } -static const struct file_operations i915_drop_caches_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_drop_caches_read, - .write = i915_drop_caches_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops, + i915_drop_caches_get, i915_drop_caches_set, + "0x%08llx\n"); -static ssize_t -i915_max_freq_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_max_freq_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; @@ -1912,42 +1812,23 @@ i915_max_freq_read(struct file *filp, if (ret) return ret; - len = snprintf(buf, sizeof(buf), - "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER); + *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_max_freq_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_max_freq_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 1, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } - - DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val); + DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) @@ -1956,30 +1837,24 @@ i915_max_freq_write(struct file *filp, /* * Turbo will still be enabled, but won't go above the set value. */ - dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER; - - gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); + do_div(val, GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.max_delay = val; + gen6_set_rps(dev, val); mutex_unlock(&dev_priv->rps.hw_lock); - return cnt; + return 0; } -static const struct file_operations i915_max_freq_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_max_freq_read, - .write = i915_max_freq_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops, + i915_max_freq_get, i915_max_freq_set, + "%llu\n"); -static ssize_t -i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, - loff_t *ppos) +static int +i915_min_freq_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; - int len, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; @@ -1988,40 +1863,23 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, if (ret) return ret; - len = snprintf(buf, sizeof(buf), - "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER); + *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, - loff_t *ppos) +static int +i915_min_freq_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; - int val = 1, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } - - DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val); + DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val); ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) @@ -2030,33 +1888,25 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, /* * Turbo will still be enabled, but won't go below the set value. */ - dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER; - - gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); + do_div(val, GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.min_delay = val; + gen6_set_rps(dev, val); mutex_unlock(&dev_priv->rps.hw_lock); - return cnt; + return 0; } -static const struct file_operations i915_min_freq_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_min_freq_read, - .write = i915_min_freq_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops, + i915_min_freq_get, i915_min_freq_set, + "%llu\n"); -static ssize_t -i915_cache_sharing_read(struct file *filp, - char __user *ubuf, - size_t max, - loff_t *ppos) +static int +i915_cache_sharing_get(void *data, u64 *val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; drm_i915_private_t *dev_priv = dev->dev_private; - char buf[80]; u32 snpcr; - int len, ret; + int ret; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; @@ -2068,46 +1918,25 @@ i915_cache_sharing_read(struct file *filp, snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); mutex_unlock(&dev_priv->dev->struct_mutex); - len = snprintf(buf, sizeof(buf), - "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >> - GEN6_MBC_SNPCR_SHIFT); + *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT; - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(ubuf, max, ppos, buf, len); + return 0; } -static ssize_t -i915_cache_sharing_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) +static int +i915_cache_sharing_set(void *data, u64 val) { - struct drm_device *dev = filp->private_data; + struct drm_device *dev = data; struct drm_i915_private *dev_priv = dev->dev_private; - char buf[20]; u32 snpcr; - int val = 1; if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - if (cnt > 0) { - if (cnt > sizeof(buf) - 1) - return -EINVAL; - - if (copy_from_user(buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = 0; - - val = simple_strtoul(buf, NULL, 0); - } - - if (val < 0 || val > 3) + if (val > 3) return -EINVAL; - DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val); + DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val); /* Update the cache sharing policy here as well */ snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); @@ -2115,16 +1944,12 @@ i915_cache_sharing_write(struct file *filp, snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); - return cnt; + return 0; } -static const struct file_operations i915_cache_sharing_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = i915_cache_sharing_read, - .write = i915_cache_sharing_write, - .llseek = default_llseek, -}; +DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops, + i915_cache_sharing_get, i915_cache_sharing_set, + "%llu\n"); /* As the drm_debugfs_init() routines are called before dev->dev_private is * allocated we need to hook into the minor for release. */ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4fa6beb..3b315ba 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1322,6 +1322,10 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; + if (INTEL_INFO(dev)->num_pipes == 0) { + dev_priv->mm.suspended = 0; + return 0; + } ret = intel_fbdev_init(dev); if (ret) @@ -1453,6 +1457,22 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv) } /** + * intel_early_sanitize_regs - clean up BIOS state + * @dev: DRM device + * + * This function must be called before we do any I915_READ or I915_WRITE. Its + * purpose is to clean up any state left by the BIOS that may affect us when + * reading and/or writing registers. + */ +static void intel_early_sanitize_regs(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_HASWELL(dev)) + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); +} + +/** * i915_driver_load - setup chip and create an initial config * @dev: DRM device * @flags: startup flags @@ -1498,6 +1518,28 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto free_priv; } + mmio_bar = IS_GEN2(dev) ? 1 : 0; + /* Before gen4, the registers and the GTT are behind different BARs. + * However, from gen4 onwards, the registers and the GTT are shared + * in the same BAR, so we want to restrict this ioremap from + * clobbering the GTT which we want ioremap_wc instead. Fortunately, + * the register BAR remains the same size for all the earlier + * generations up to Ironlake. + */ + if (info->gen < 5) + mmio_size = 512*1024; + else + mmio_size = 2*1024*1024; + + dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); + if (!dev_priv->regs) { + DRM_ERROR("failed to map registers\n"); + ret = -EIO; + goto put_bridge; + } + + intel_early_sanitize_regs(dev); + ret = i915_gem_gtt_init(dev); if (ret) goto put_bridge; @@ -1522,26 +1564,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); - mmio_bar = IS_GEN2(dev) ? 1 : 0; - /* Before gen4, the registers and the GTT are behind different BARs. - * However, from gen4 onwards, the registers and the GTT are shared - * in the same BAR, so we want to restrict this ioremap from - * clobbering the GTT which we want ioremap_wc instead. Fortunately, - * the register BAR remains the same size for all the earlier - * generations up to Ironlake. - */ - if (info->gen < 5) - mmio_size = 512*1024; - else - mmio_size = 2*1024*1024; - - dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); - if (!dev_priv->regs) { - DRM_ERROR("failed to map registers\n"); - ret = -EIO; - goto put_gmch; - } - aperture_size = dev_priv->gtt.mappable_end; dev_priv->gtt.mappable = @@ -1612,16 +1634,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) mutex_init(&dev_priv->rps.hw_lock); mutex_init(&dev_priv->modeset_restore_lock); - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) - dev_priv->num_pipe = 3; - else if (IS_MOBILE(dev) || !IS_GEN2(dev)) - dev_priv->num_pipe = 2; - else - dev_priv->num_pipe = 1; + dev_priv->num_plane = 1; + if (IS_VALLEYVIEW(dev)) + dev_priv->num_plane = 2; - ret = drm_vblank_init(dev, dev_priv->num_pipe); - if (ret) - goto out_gem_unload; + if (INTEL_INFO(dev)->num_pipes) { + ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes); + if (ret) + goto out_gem_unload; + } /* Start out suspended */ dev_priv->mm.suspended = 1; @@ -1636,9 +1657,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) i915_setup_sysfs(dev); - /* Must be done after probing outputs */ - intel_opregion_init(dev); - acpi_video_register(); + if (INTEL_INFO(dev)->num_pipes) { + /* Must be done after probing outputs */ + intel_opregion_init(dev); + acpi_video_register(); + } if (IS_GEN5(dev)) intel_gpu_ips_init(dev_priv); @@ -1663,10 +1686,9 @@ out_mtrrfree: dev_priv->mm.gtt_mtrr = -1; } io_mapping_free(dev_priv->gtt.mappable); + dev_priv->gtt.gtt_remove(dev); out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); -put_gmch: - dev_priv->gtt.gtt_remove(dev); put_bridge: pci_dev_put(dev_priv->bridge_dev); free_priv: diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e9b5789..9ebe895 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -121,9 +121,7 @@ MODULE_PARM_DESC(i915_enable_ppgtt, unsigned int i915_preliminary_hw_support __read_mostly = 0; module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); MODULE_PARM_DESC(preliminary_hw_support, - "Enable preliminary hardware support. " - "Enable Haswell and ValleyView Support. " - "(default: false)"); + "Enable preliminary hardware support. (default: false)"); int i915_disable_power_well __read_mostly = 0; module_param_named(disable_power_well, i915_disable_power_well, int, 0600); @@ -142,75 +140,85 @@ extern int intel_agp_enabled; .subdevice = PCI_ANY_ID, \ .driver_data = (unsigned long) info } +#define INTEL_QUANTA_VGA_DEVICE(info) { \ + .class = PCI_BASE_CLASS_DISPLAY << 16, \ + .class_mask = 0xff0000, \ + .vendor = 0x8086, \ + .device = 0x16a, \ + .subvendor = 0x152d, \ + .subdevice = 0x8990, \ + .driver_data = (unsigned long) info } + + static const struct intel_device_info intel_i830_info = { - .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, + .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { - .gen = 2, + .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i85x_info = { - .gen = 2, .is_i85x = 1, .is_mobile = 1, + .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i865g_info = { - .gen = 2, + .gen = 2, .num_pipes = 1, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915g_info = { - .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, + .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { - .gen = 3, .is_mobile = 1, + .gen = 3, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, }; static const struct intel_device_info intel_i945g_info = { - .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, + .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { - .gen = 3, .is_i945gm = 1, .is_mobile = 1, + .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2, .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, }; static const struct intel_device_info intel_i965g_info = { - .gen = 4, .is_broadwater = 1, + .gen = 4, .is_broadwater = 1, .num_pipes = 2, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_i965gm_info = { - .gen = 4, .is_crestline = 1, + .gen = 4, .is_crestline = 1, .num_pipes = 2, .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, .has_overlay = 1, .supports_tv = 1, }; static const struct intel_device_info intel_g33_info = { - .gen = 3, .is_g33 = 1, + .gen = 3, .is_g33 = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_g45_info = { - .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, + .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2, .has_pipe_cxsr = 1, .has_hotplug = 1, .has_bsd_ring = 1, }; static const struct intel_device_info intel_gm45_info = { - .gen = 4, .is_g4x = 1, + .gen = 4, .is_g4x = 1, .num_pipes = 2, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, .supports_tv = 1, @@ -218,26 +226,26 @@ static const struct intel_device_info intel_gm45_info = { }; static const struct intel_device_info intel_pineview_info = { - .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, + .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_overlay = 1, }; static const struct intel_device_info intel_ironlake_d_info = { - .gen = 5, + .gen = 5, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, }; static const struct intel_device_info intel_ironlake_m_info = { - .gen = 5, .is_mobile = 1, + .gen = 5, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { - .gen = 6, + .gen = 6, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_bsd_ring = 1, .has_blt_ring = 1, @@ -246,7 +254,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { }; static const struct intel_device_info intel_sandybridge_m_info = { - .gen = 6, .is_mobile = 1, + .gen = 6, .is_mobile = 1, .num_pipes = 2, .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 1, .has_bsd_ring = 1, @@ -255,61 +263,57 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_force_wake = 1, }; +#define GEN7_FEATURES \ + .gen = 7, .num_pipes = 3, \ + .need_gfx_hws = 1, .has_hotplug = 1, \ + .has_bsd_ring = 1, \ + .has_blt_ring = 1, \ + .has_llc = 1, \ + .has_force_wake = 1 + static const struct intel_device_info intel_ivybridge_d_info = { - .is_ivybridge = 1, .gen = 7, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_ivybridge = 1, }; static const struct intel_device_info intel_ivybridge_m_info = { - .is_ivybridge = 1, .gen = 7, .is_mobile = 1, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */ - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_ivybridge = 1, + .is_mobile = 1, +}; + +static const struct intel_device_info intel_ivybridge_q_info = { + GEN7_FEATURES, + .is_ivybridge = 1, + .num_pipes = 0, /* legal, last one wins */ }; static const struct intel_device_info intel_valleyview_m_info = { - .gen = 7, .is_mobile = 1, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_fbc = 0, - .has_bsd_ring = 1, - .has_blt_ring = 1, + GEN7_FEATURES, + .is_mobile = 1, + .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_llc = 0, /* legal, last one wins */ }; static const struct intel_device_info intel_valleyview_d_info = { - .gen = 7, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_fbc = 0, - .has_bsd_ring = 1, - .has_blt_ring = 1, + GEN7_FEATURES, + .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_llc = 0, /* legal, last one wins */ }; static const struct intel_device_info intel_haswell_d_info = { - .is_haswell = 1, .gen = 7, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_haswell = 1, }; static const struct intel_device_info intel_haswell_m_info = { - .is_haswell = 1, .gen = 7, .is_mobile = 1, - .need_gfx_hws = 1, .has_hotplug = 1, - .has_bsd_ring = 1, - .has_blt_ring = 1, - .has_llc = 1, - .has_force_wake = 1, + GEN7_FEATURES, + .is_haswell = 1, + .is_mobile = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ @@ -356,6 +360,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ + INTEL_QUANTA_VGA_DEVICE(&intel_ivybridge_q_info), /* Quanta transcode */ INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ @@ -394,6 +399,9 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), + INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info), + INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info), + INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), {0, 0, 0} @@ -408,6 +416,15 @@ void intel_detect_pch(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct pci_dev *pch; + /* In all current cases, num_pipes is equivalent to the PCH_NOP setting + * (which really amounts to a PCH but no South Display). + */ + if (INTEL_INFO(dev)->num_pipes == 0) { + dev_priv->pch_type = PCH_NOP; + dev_priv->num_pch_pll = 0; + return; + } + /* * The reason to probe ISA bridge instead of Dev31:Fun0 is to * make graphics device passthrough work easy for VMM, that only @@ -442,11 +459,13 @@ void intel_detect_pch(struct drm_device *dev) dev_priv->num_pch_pll = 0; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); WARN_ON(!IS_HASWELL(dev)); + WARN_ON(IS_ULT(dev)); } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; dev_priv->num_pch_pll = 0; DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); + WARN_ON(!IS_ULT(dev)); } BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); } @@ -474,6 +493,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; /* ignore lid events during suspend */ mutex_lock(&dev_priv->modeset_restore_lock); @@ -497,10 +517,14 @@ static int i915_drm_freeze(struct drm_device *dev) cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); - intel_modeset_disable(dev); - drm_irq_uninstall(dev); dev_priv->enable_hotplug_processing = false; + /* + * Disable CRTCs directly since we want to preserve sw state + * for _thaw. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + dev_priv->display.crtc_disable(crtc); } i915_save_state(dev); @@ -556,6 +580,24 @@ void intel_console_resume(struct work_struct *work) console_unlock(); } +static void intel_resume_hotplug(struct drm_device *dev) +{ + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; + + mutex_lock(&mode_config->mutex); + DRM_DEBUG_KMS("running encoder hotplug functions\n"); + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) + if (encoder->hot_plug) + encoder->hot_plug(encoder); + + mutex_unlock(&mode_config->mutex); + + /* Just fire off a uevent and let userspace tell us what to do */ + drm_helper_hpd_irq_event(dev); +} + static int __i915_drm_thaw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -578,7 +620,10 @@ static int __i915_drm_thaw(struct drm_device *dev) drm_irq_install(dev); intel_modeset_init_hw(dev); - intel_modeset_setup_hw_state(dev, false); + + drm_modeset_lock_all(dev); + intel_modeset_setup_hw_state(dev, true); + drm_modeset_unlock_all(dev); /* * ... but also need to make sure that hotplug processing @@ -588,6 +633,8 @@ static int __i915_drm_thaw(struct drm_device *dev) * */ intel_hpd_init(dev); dev_priv->enable_hotplug_processing = true; + /* Config may have changed between suspend and resume */ + intel_resume_hotplug(dev); } intel_opregion_init(dev); @@ -732,6 +779,7 @@ static int ironlake_do_reset(struct drm_device *dev) int ret; gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + gdrst &= ~GRDOM_MASK; I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); @@ -740,6 +788,7 @@ static int ironlake_do_reset(struct drm_device *dev) /* We can't reset render&media without also resetting display ... */ gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + gdrst &= ~GRDOM_MASK; I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); @@ -803,7 +852,7 @@ int intel_gpu_reset(struct drm_device *dev) /* Also reset the gpu hangman. */ if (dev_priv->gpu_error.stop_rings) { - DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); + 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 " @@ -882,7 +931,11 @@ int i915_reset(struct drm_device *dev) ring->init(ring); i915_gem_context_init(dev); - i915_gem_init_ppgtt(dev); + if (dev_priv->mm.aliasing_ppgtt) { + ret = dev_priv->mm.aliasing_ppgtt->enable(dev); + if (ret) + i915_gem_cleanup_aliasing_ppgtt(dev); + } /* * It would make sense to re-init all the other hw state, at @@ -1147,6 +1200,27 @@ ilk_dummy_write(struct drm_i915_private *dev_priv) I915_WRITE_NOTRACE(MI_MODE, 0); } +static void +hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) +{ + if (IS_HASWELL(dev_priv->dev) && + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { + DRM_ERROR("Unknown unclaimed register before writing to %x\n", + reg); + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); + } +} + +static void +hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) +{ + if (IS_HASWELL(dev_priv->dev) && + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { + DRM_ERROR("Unclaimed write to %x\n", reg); + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); + } +} + #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ @@ -1183,18 +1257,12 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ } \ if (IS_GEN5(dev_priv->dev)) \ ilk_dummy_write(dev_priv); \ - if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ - DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ - I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ - } \ + hsw_unclaimed_reg_clear(dev_priv, reg); \ write##y(val, dev_priv->regs + reg); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ - if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ - DRM_ERROR("Unclaimed write to %x\n", reg); \ - writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); \ - } \ + hsw_unclaimed_reg_check(dev_priv, reg); \ } __i915_write(8, b) __i915_write(16, w) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 01769e2..d5dcf7f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -86,6 +86,19 @@ enum port { }; #define port_name(p) ((p) + 'A') +enum hpd_pin { + HPD_NONE = 0, + HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ + HPD_TV = HPD_NONE, /* TV is known to be unreliable */ + HPD_CRT, + HPD_SDVO_B, + HPD_SDVO_C, + HPD_PORT_B, + HPD_PORT_C, + HPD_PORT_D, + HPD_NUM_PINS +}; + #define I915_GEM_GPU_DOMAINS \ (I915_GEM_DOMAIN_RENDER | \ I915_GEM_DOMAIN_SAMPLER | \ @@ -93,7 +106,7 @@ enum port { I915_GEM_DOMAIN_INSTRUCTION | \ I915_GEM_DOMAIN_VERTEX) -#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) +#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++) #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ @@ -182,9 +195,9 @@ struct drm_i915_master_private { struct _drm_i915_sarea *sarea_priv; }; #define I915_FENCE_REG_NONE -1 -#define I915_MAX_NUM_FENCES 16 -/* 16 fences + sign bit for FENCE_REG_NONE */ -#define I915_MAX_NUM_FENCE_BITS 5 +#define I915_MAX_NUM_FENCES 32 +/* 32 fences + sign bit for FENCE_REG_NONE */ +#define I915_MAX_NUM_FENCE_BITS 6 struct drm_i915_fence_reg { struct list_head lru_list; @@ -243,7 +256,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer; + } *ringbuffer, *batchbuffer, *ctx; struct drm_i915_error_request { long jiffies; u32 seqno; @@ -271,6 +284,9 @@ struct drm_i915_error_state { struct intel_display_error_state *display; }; +struct intel_crtc_config; +struct intel_crtc; + struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); @@ -283,9 +299,11 @@ struct drm_i915_display_funcs { void (*update_linetime_wm)(struct drm_device *dev, int pipe, struct drm_display_mode *mode); void (*modeset_global_resources)(struct drm_device *dev); + /* Returns the active state of the crtc, and if the crtc is active, + * fills out the pipe-config with the hw state. */ + bool (*get_pipe_config)(struct intel_crtc *, + struct intel_crtc_config *); int (*crtc_mode_set)(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); void (*crtc_enable)(struct drm_crtc *crtc); @@ -341,6 +359,7 @@ struct drm_i915_gt_funcs { struct intel_device_info { u32 display_mmio_offset; + u8 num_pipes:3; u8 gen; u8 is_mobile:1; u8 is_i85x:1; @@ -430,6 +449,7 @@ struct i915_hw_ppgtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); + int (*enable)(struct drm_device *dev); void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; @@ -460,6 +480,7 @@ enum intel_pch { PCH_IBX, /* Ibexpeak PCH */ PCH_CPT, /* Cougarpoint PCH */ PCH_LPT, /* Lynxpoint PCH */ + PCH_NOP, }; enum intel_sbi_destination { @@ -647,6 +668,7 @@ struct intel_gen6_power_mgmt { u8 cur_delay; u8 min_delay; u8 max_delay; + u8 hw_max; struct delayed_work delayed_resume_work; @@ -905,16 +927,24 @@ typedef struct drm_i915_private { struct mutex dpio_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 pipestat[2]; u32 irq_mask; u32 gt_irq_mask; - u32 hotplug_supported_mask; struct work_struct hotplug_work; bool enable_hotplug_processing; + struct { + unsigned long hpd_last_jiffies; + int hpd_cnt; + enum { + HPD_ENABLED = 0, + HPD_DISABLED = 1, + HPD_MARK_DISABLED = 2 + } hpd_mark; + } hpd_stats[HPD_NUM_PINS]; + struct timer_list hotplug_reenable_timer; - int num_pipe; int num_pch_pll; + int num_plane; unsigned long cfb_size; unsigned int cfb_fb; @@ -928,9 +958,14 @@ typedef struct drm_i915_private { struct intel_overlay *overlay; unsigned int sprite_scaling_enabled; + /* backlight */ + struct { + int level; + bool enabled; + struct backlight_device *device; + } backlight; + /* LVDS info */ - int backlight_level; /* restore backlight to this value */ - bool backlight_enabled; struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ @@ -941,6 +976,7 @@ typedef struct drm_i915_private { unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; unsigned int display_clock_mode:1; + unsigned int fdi_rx_polarity_inverted:1; int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ struct { @@ -1032,8 +1068,6 @@ typedef struct drm_i915_private { */ struct work_struct console_resume_work; - struct backlight_device *backlight; - struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; @@ -1340,6 +1374,7 @@ struct drm_i915_file_private { #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define HAS_DDI(dev) (IS_HASWELL(dev)) +#define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 @@ -1352,6 +1387,7 @@ struct drm_i915_file_private { #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) +#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP) #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE) #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) @@ -1529,17 +1565,12 @@ void i915_gem_lastclose(struct drm_device *dev); int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) { - struct scatterlist *sg = obj->pages->sgl; - int nents = obj->pages->nents; - while (nents > SG_MAX_SINGLE_ALLOC) { - if (n < SG_MAX_SINGLE_ALLOC - 1) - break; - - sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1); - n -= SG_MAX_SINGLE_ALLOC - 1; - nents -= SG_MAX_SINGLE_ALLOC - 1; - } - return sg_page(sg+n); + struct sg_page_iter sg_iter; + + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n) + return sg_page_iter_page(&sg_iter); + + return NULL; } static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) { @@ -1624,7 +1655,6 @@ int __must_check i915_gem_init(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); void i915_gem_l3_remap(struct drm_device *dev); void i915_gem_init_swizzling(struct drm_device *dev); -void i915_gem_init_ppgtt(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); @@ -1718,6 +1748,11 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev); void i915_gem_cleanup_stolen(struct drm_device *dev); struct drm_i915_gem_object * i915_gem_object_create_stolen(struct drm_device *dev, u32 size); +struct drm_i915_gem_object * +i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, + u32 stolen_offset, + u32 gtt_offset, + u32 size); void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); /* i915_gem_tiling.c */ @@ -1848,6 +1883,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); 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); +int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); +int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); @@ -1901,4 +1938,9 @@ static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) return VGACNTRL; } +static inline void __user *to_user_ptr(u64 address) +{ + return (void __user *)(uintptr_t)address; +} + #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0e207e6..6be940e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -411,10 +411,9 @@ i915_gem_shmem_pread(struct drm_device *dev, int obj_do_bit17_swizzling, page_do_bit17_swizzling; int prefaulted = 0; int needs_clflush = 0; - struct scatterlist *sg; - int i; + struct sg_page_iter sg_iter; - user_data = (char __user *) (uintptr_t) args->data_ptr; + user_data = to_user_ptr(args->data_ptr); remain = args->size; obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); @@ -441,11 +440,9 @@ i915_gem_shmem_pread(struct drm_device *dev, offset = args->offset; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { - struct page *page; - - if (i < offset >> PAGE_SHIFT) - continue; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, + offset >> PAGE_SHIFT) { + struct page *page = sg_page_iter_page(&sg_iter); if (remain <= 0) break; @@ -460,7 +457,6 @@ i915_gem_shmem_pread(struct drm_device *dev, if ((shmem_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - shmem_page_offset; - page = sg_page(sg); page_do_bit17_swizzling = obj_do_bit17_swizzling && (page_to_phys(page) & (1 << 17)) != 0; @@ -522,7 +518,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return 0; if (!access_ok(VERIFY_WRITE, - (char __user *)(uintptr_t)args->data_ptr, + to_user_ptr(args->data_ptr), args->size)) return -EFAULT; @@ -613,7 +609,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, if (ret) goto out_unpin; - user_data = (char __user *) (uintptr_t) args->data_ptr; + user_data = to_user_ptr(args->data_ptr); remain = args->size; offset = obj->gtt_offset + args->offset; @@ -732,10 +728,9 @@ i915_gem_shmem_pwrite(struct drm_device *dev, int hit_slowpath = 0; int needs_clflush_after = 0; int needs_clflush_before = 0; - int i; - struct scatterlist *sg; + struct sg_page_iter sg_iter; - user_data = (char __user *) (uintptr_t) args->data_ptr; + user_data = to_user_ptr(args->data_ptr); remain = args->size; obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); @@ -768,13 +763,11 @@ i915_gem_shmem_pwrite(struct drm_device *dev, offset = args->offset; obj->dirty = 1; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { - struct page *page; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, + offset >> PAGE_SHIFT) { + struct page *page = sg_page_iter_page(&sg_iter); int partial_cacheline_write; - if (i < offset >> PAGE_SHIFT) - continue; - if (remain <= 0) break; @@ -796,7 +789,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev, ((shmem_page_offset | page_length) & (boot_cpu_data.x86_clflush_size - 1)); - page = sg_page(sg); page_do_bit17_swizzling = obj_do_bit17_swizzling && (page_to_phys(page) & (1 << 17)) != 0; @@ -867,11 +859,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, return 0; if (!access_ok(VERIFY_READ, - (char __user *)(uintptr_t)args->data_ptr, + to_user_ptr(args->data_ptr), args->size)) return -EFAULT; - ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr, + ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr), args->size); if (ret) return -EFAULT; @@ -1633,9 +1625,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) static void i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) { - int page_count = obj->base.size / PAGE_SIZE; - struct scatterlist *sg; - int ret, i; + struct sg_page_iter sg_iter; + int ret; BUG_ON(obj->madv == __I915_MADV_PURGED); @@ -1655,8 +1646,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) if (obj->madv == I915_MADV_DONTNEED) obj->dirty = 0; - for_each_sg(obj->pages->sgl, sg, page_count, i) { - struct page *page = sg_page(sg); + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_page_iter_page(&sg_iter); if (obj->dirty) set_page_dirty(page); @@ -1757,7 +1748,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) struct address_space *mapping; struct sg_table *st; struct scatterlist *sg; + struct sg_page_iter sg_iter; struct page *page; + unsigned long last_pfn = 0; /* suppress gcc warning */ gfp_t gfp; /* Assert that the object is not currently in any GPU domain. As it @@ -1787,7 +1780,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp = mapping_gfp_mask(mapping); gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp &= ~(__GFP_IO | __GFP_WAIT); - for_each_sg(st->sgl, sg, page_count, i) { + sg = st->sgl; + st->nents = 0; + for (i = 0; i < page_count; i++) { page = shmem_read_mapping_page_gfp(mapping, i, gfp); if (IS_ERR(page)) { i915_gem_purge(dev_priv, page_count); @@ -1810,9 +1805,18 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp &= ~(__GFP_IO | __GFP_WAIT); } - sg_set_page(sg, page, PAGE_SIZE, 0); + if (!i || page_to_pfn(page) != last_pfn + 1) { + if (i) + sg = sg_next(sg); + st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + } else { + sg->length += PAGE_SIZE; + } + last_pfn = page_to_pfn(page); } + sg_mark_end(sg); obj->pages = st; if (i915_gem_object_needs_bit17_swizzle(obj)) @@ -1821,8 +1825,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) return 0; err_pages: - for_each_sg(st->sgl, sg, i, page_count) - page_cache_release(sg_page(sg)); + sg_mark_end(sg); + for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) + page_cache_release(sg_page_iter_page(&sg_iter)); sg_free_table(st); kfree(st); return PTR_ERR(page); @@ -2123,11 +2128,11 @@ static void i915_gem_reset_fences(struct drm_device *dev) for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - i915_gem_write_fence(dev, i, NULL); - if (reg->obj) i915_gem_object_fence_lost(reg->obj); + i915_gem_write_fence(dev, i, NULL); + reg->pin_count = 0; reg->obj = NULL; INIT_LIST_HEAD(®->lru_list); @@ -2678,17 +2683,35 @@ static inline int fence_number(struct drm_i915_private *dev_priv, return fence - dev_priv->fence_regs; } +static void i915_gem_write_fence__ipi(void *data) +{ + wbinvd(); +} + static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - int reg = fence_number(dev_priv, fence); - - i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int fence_reg = fence_number(dev_priv, fence); + + /* In order to fully serialize access to the fenced region and + * the update to the fence register we need to take extreme + * measures on SNB+. In theory, the write to the fence register + * flushes all memory transactions before, and coupled with the + * mb() placed around the register write we serialise all memory + * operations with respect to the changes in the tiler. Yet, on + * SNB+ we need to take a step further and emit an explicit wbinvd() + * on each processor in order to manually flush all memory + * transactions before updating the fence register. + */ + if (HAS_LLC(obj->base.dev)) + on_each_cpu(i915_gem_write_fence__ipi, NULL, 1); + i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); if (enable) { - obj->fence_reg = reg; + obj->fence_reg = fence_reg; fence->obj = obj; list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); } else { @@ -2717,6 +2740,7 @@ int i915_gem_object_put_fence(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct drm_i915_fence_reg *fence; int ret; ret = i915_gem_object_wait_fence(obj); @@ -2726,10 +2750,10 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) if (obj->fence_reg == I915_FENCE_REG_NONE) return 0; - i915_gem_object_update_fence(obj, - &dev_priv->fence_regs[obj->fence_reg], - false); + fence = &dev_priv->fence_regs[obj->fence_reg]; + i915_gem_object_fence_lost(obj); + i915_gem_object_update_fence(obj, fence, false); return 0; } @@ -3986,6 +4010,12 @@ i915_gem_init_hw(struct drm_device *dev) if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); + if (HAS_PCH_NOP(dev)) { + u32 temp = I915_READ(GEN7_MSG_CTL); + temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); + I915_WRITE(GEN7_MSG_CTL, temp); + } + i915_gem_l3_remap(dev); i915_gem_init_swizzling(dev); @@ -3999,7 +4029,13 @@ i915_gem_init_hw(struct drm_device *dev) * contexts before PPGTT. */ i915_gem_context_init(dev); - i915_gem_init_ppgtt(dev); + if (dev_priv->mm.aliasing_ppgtt) { + ret = dev_priv->mm.aliasing_ppgtt->enable(dev); + if (ret) { + i915_gem_cleanup_aliasing_ppgtt(dev); + DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); + } + } return 0; } @@ -4010,7 +4046,16 @@ int i915_gem_init(struct drm_device *dev) int ret; mutex_lock(&dev->struct_mutex); + + if (IS_VALLEYVIEW(dev)) { + /* VLVA0 (potential hack), BIOS isn't actually waking us */ + I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); + if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) + DRM_DEBUG_DRIVER("allow wake ack timed out\n"); + } + i915_gem_init_global_gtt(dev); + ret = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); if (ret) { @@ -4145,7 +4190,9 @@ i915_gem_load(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; - if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) + dev_priv->num_fence_regs = 32; + else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) dev_priv->num_fence_regs = 16; else dev_priv->num_fence_regs = 8; @@ -4327,7 +4374,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_file *file_priv) { void *vaddr = obj->phys_obj->handle->vaddr + args->offset; - char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; + char __user *user_data = to_user_ptr(args->data_ptr); if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { unsigned long unwritten; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 94d873a..a1e8ecb 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -152,6 +152,13 @@ create_hw_context(struct drm_device *dev, return ERR_PTR(-ENOMEM); } + if (INTEL_INFO(dev)->gen >= 7) { + ret = i915_gem_object_set_cache_level(ctx->obj, + I915_CACHE_LLC_MLC); + if (ret) + goto err_out; + } + /* The ring associated with the context object is handled by the normal * object tracking code. We give an initial ring value simple to pass an * assertion in the context switch code. diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 6a5af68..dc53a52 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -62,7 +62,7 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme src = obj->pages->sgl; dst = st->sgl; for (i = 0; i < obj->pages->nents; i++) { - sg_set_page(dst, sg_page(src), PAGE_SIZE, 0); + sg_set_page(dst, sg_page(src), src->length, 0); dst = sg_next(dst); src = sg_next(src); } @@ -105,7 +105,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) { struct drm_i915_gem_object *obj = dma_buf->priv; struct drm_device *dev = obj->base.dev; - struct scatterlist *sg; + struct sg_page_iter sg_iter; struct page **pages; int ret, i; @@ -124,14 +124,15 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) ret = -ENOMEM; - pages = drm_malloc_ab(obj->pages->nents, sizeof(struct page *)); + pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages)); if (pages == NULL) goto error; - for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) - pages[i] = sg_page(sg); + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) + pages[i++] = sg_page_iter_page(&sg_iter); - obj->dma_buf_vmapping = vmap(pages, obj->pages->nents, 0, PAGE_KERNEL); + obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL); drm_free_large(pages); if (!obj->dma_buf_vmapping) @@ -271,7 +272,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, * refcount on gem itself instead of f_count of dmabuf. */ drm_gem_object_reference(&obj->base); - dma_buf_put(dma_buf); return &obj->base; } } @@ -281,6 +281,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, if (IS_ERR(attach)) return ERR_CAST(attach); + get_dma_buf(dma_buf); + obj = i915_gem_object_alloc(dev); if (obj == NULL) { ret = -ENOMEM; @@ -300,5 +302,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, fail_detach: dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9a48e1a..117ce38 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -305,7 +305,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; int remain, ret; - user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; + user_relocs = to_user_ptr(entry->relocs_ptr); remain = entry->relocation_count; while (remain) { @@ -359,8 +359,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, } static int -i915_gem_execbuffer_relocate(struct drm_device *dev, - struct eb_objects *eb) +i915_gem_execbuffer_relocate(struct eb_objects *eb) { struct drm_i915_gem_object *obj; int ret = 0; @@ -475,7 +474,6 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, - struct drm_file *file, struct list_head *objects, bool *need_relocs) { @@ -618,7 +616,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, u64 invalid_offset = (u64)-1; int j; - user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; + user_relocs = to_user_ptr(exec[i].relocs_ptr); if (copy_from_user(reloc+total, user_relocs, exec[i].relocation_count * sizeof(*reloc))) { @@ -663,7 +661,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); if (ret) goto err; @@ -736,7 +734,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); for (i = 0; i < count; i++) { - char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; + char __user *ptr = to_user_ptr(exec[i].relocs_ptr); int length; /* limited by fault_in_pages_readable() */ if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) @@ -752,7 +750,11 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry); - /* we may also need to update the presumed offsets */ + /* + * We must check that the entire relocation array is safe + * to read, but since we may need to update the presumed + * offsets during execution, check for full write access. + */ if (!access_ok(VERIFY_WRITE, ptr, length)) return -EFAULT; @@ -949,9 +951,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (copy_from_user(cliprects, - (struct drm_clip_rect __user *)(uintptr_t) - args->cliprects_ptr, - sizeof(*cliprects)*args->num_cliprects)) { + to_user_ptr(args->cliprects_ptr), + sizeof(*cliprects)*args->num_cliprects)) { ret = -EFAULT; goto pre_mutex_err; } @@ -986,13 +987,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Move the objects en-masse into the GTT, evicting if necessary. */ need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ if (need_relocs) - ret = i915_gem_execbuffer_relocate(dev, eb); + ret = i915_gem_execbuffer_relocate(eb); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, @@ -1115,7 +1116,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, return -ENOMEM; } ret = copy_from_user(exec_list, - (void __user *)(uintptr_t)args->buffers_ptr, + to_user_ptr(args->buffers_ptr), sizeof(*exec_list) * args->buffer_count); if (ret != 0) { DRM_DEBUG("copy %d exec entries failed %d\n", @@ -1154,7 +1155,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, for (i = 0; i < args->buffer_count; i++) exec_list[i].offset = exec2_list[i].offset; /* ... and back out to userspace */ - ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr, + ret = copy_to_user(to_user_ptr(args->buffers_ptr), exec_list, sizeof(*exec_list) * args->buffer_count); if (ret) { @@ -1195,8 +1196,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, return -ENOMEM; } ret = copy_from_user(exec2_list, - (struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, + to_user_ptr(args->buffers_ptr), sizeof(*exec2_list) * args->buffer_count); if (ret != 0) { DRM_DEBUG("copy %d exec entries failed %d\n", @@ -1208,7 +1208,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ - ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr, + ret = copy_to_user(to_user_ptr(args->buffers_ptr), exec2_list, sizeof(*exec2_list) * args->buffer_count); if (ret) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 926a1e2..dca614d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -28,7 +28,7 @@ #include "i915_trace.h" #include "intel_drv.h" -typedef uint32_t gtt_pte_t; +typedef uint32_t gen6_gtt_pte_t; /* PPGTT stuff */ #define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) @@ -44,11 +44,11 @@ typedef uint32_t gtt_pte_t; #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) +static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) { - gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = GEN6_PTE_VALID; pte |= GEN6_PTE_ADDR_ENCODE(addr); switch (level) { @@ -72,18 +72,85 @@ static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, BUG(); } - return pte; } +static int gen6_ppgtt_enable(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t pd_offset; + struct intel_ring_buffer *ring; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + gen6_gtt_pte_t __iomem *pd_addr; + uint32_t pd_entry; + int i; + + pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm + + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; + + pt_addr = ppgtt->pt_dma_addr[i]; + pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); + pd_entry |= GEN6_PDE_VALID; + + writel(pd_entry, pd_addr + i); + } + readl(pd_addr); + + pd_offset = ppgtt->pd_offset; + pd_offset /= 64; /* in cachelines, */ + pd_offset <<= 16; + + if (INTEL_INFO(dev)->gen == 6) { + uint32_t ecochk, gab_ctl, ecobits; + + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | + ECOBITS_PPGTT_CACHE64B); + + gab_ctl = I915_READ(GAB_CTL); + I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); + + ecochk = I915_READ(GAM_ECOCHK); + I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | + ECOCHK_PPGTT_CACHE64B); + I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + } else if (INTEL_INFO(dev)->gen >= 7) { + uint32_t ecochk, ecobits; + + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); + + ecochk = I915_READ(GAM_ECOCHK); + if (IS_HASWELL(dev)) { + ecochk |= ECOCHK_PPGTT_WB_HSW; + } else { + ecochk |= ECOCHK_PPGTT_LLC_IVB; + ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; + } + I915_WRITE(GAM_ECOCHK, ecochk); + /* GFX_MODE is per-ring on gen7+ */ + } + + for_each_ring(ring, dev_priv, i) { + if (INTEL_INFO(dev)->gen >= 7) + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); + I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); + } + return 0; +} + /* PPGTT support for Sandybdrige/Gen6 and later */ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { - gtt_pte_t *pt_vaddr; - gtt_pte_t scratch_pte; - unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; + gen6_gtt_pte_t *pt_vaddr, scratch_pte; + unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; @@ -96,7 +163,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, if (last_pte > I915_PPGTT_PT_ENTRIES) last_pte = I915_PPGTT_PT_ENTRIES; - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); for (i = first_pte; i < last_pte; i++) pt_vaddr[i] = scratch_pte; @@ -105,7 +172,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, num_entries -= last_pte - first_pte; first_pte = 0; - act_pd++; + act_pt++; } } @@ -114,43 +181,27 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, enum i915_cache_level cache_level) { - gtt_pte_t *pt_vaddr; - unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; - unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; - unsigned i, j, m, segment_len; - dma_addr_t page_addr; - struct scatterlist *sg; - - /* init sg walking */ - sg = pages->sgl; - i = 0; - segment_len = sg_dma_len(sg) >> PAGE_SHIFT; - m = 0; - - while (i < pages->nents) { - pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); - - for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { - page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr, - cache_level); - - /* grab the next page */ - if (++m == segment_len) { - if (++i == pages->nents) - break; - - sg = sg_next(sg); - segment_len = sg_dma_len(sg) >> PAGE_SHIFT; - m = 0; - } - } + gen6_gtt_pte_t *pt_vaddr; + unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; + unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; + struct sg_page_iter sg_iter; - kunmap_atomic(pt_vaddr); + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); + for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { + dma_addr_t page_addr; - first_pte = 0; - act_pd++; + page_addr = sg_page_iter_dma_address(&sg_iter); + pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, + cache_level); + if (++act_pte == I915_PPGTT_PT_ENTRIES) { + kunmap_atomic(pt_vaddr); + act_pt++; + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); + act_pte = 0; + + } } + kunmap_atomic(pt_vaddr); } static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) @@ -182,10 +233,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 * entries. For aliasing ppgtt support we just steal them at the end for * now. */ - first_pd_entry_in_global_pt = - gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; + first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt); ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; + ppgtt->enable = gen6_ppgtt_enable; ppgtt->clear_range = gen6_ppgtt_clear_range; ppgtt->insert_entries = gen6_ppgtt_insert_entries; ppgtt->cleanup = gen6_ppgtt_cleanup; @@ -219,12 +270,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->pt_dma_addr[i] = pt_addr; } - ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; - ppgtt->clear_range(ppgtt, 0, ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); - ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); + ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); return 0; @@ -256,8 +305,13 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) return -ENOMEM; ppgtt->dev = dev; + ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; + + if (INTEL_INFO(dev)->gen < 8) + ret = gen6_ppgtt_init(ppgtt); + else + BUG(); - ret = gen6_ppgtt_init(ppgtt); if (ret) kfree(ppgtt); else @@ -275,6 +329,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) return; ppgtt->cleanup(ppgtt); + dev_priv->mm.aliasing_ppgtt = NULL; } void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, @@ -294,64 +349,6 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, obj->base.size >> PAGE_SHIFT); } -void i915_gem_init_ppgtt(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t pd_offset; - struct intel_ring_buffer *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - gtt_pte_t __iomem *pd_addr; - uint32_t pd_entry; - int i; - - if (!dev_priv->mm.aliasing_ppgtt) - return; - - - pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); - for (i = 0; i < ppgtt->num_pd_entries; i++) { - dma_addr_t pt_addr; - - pt_addr = ppgtt->pt_dma_addr[i]; - pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); - pd_entry |= GEN6_PDE_VALID; - - writel(pd_entry, pd_addr + i); - } - readl(pd_addr); - - pd_offset = ppgtt->pd_offset; - pd_offset /= 64; /* in cachelines, */ - pd_offset <<= 16; - - if (INTEL_INFO(dev)->gen == 6) { - uint32_t ecochk, gab_ctl, ecobits; - - ecobits = I915_READ(GAC_ECO_BITS); - I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); - - gab_ctl = I915_READ(GAB_CTL); - I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); - - ecochk = I915_READ(GAM_ECOCHK); - I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | - ECOCHK_PPGTT_CACHE64B); - I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - } else if (INTEL_INFO(dev)->gen >= 7) { - I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); - /* GFX_MODE is per-ring on gen7+ */ - } - - for_each_ring(ring, dev_priv, i) { - if (INTEL_INFO(dev)->gen >= 7) - I915_WRITE(RING_MODE_GEN7(ring), - _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - - I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); - } -} - extern int intel_iommu_gfx_mapped; /* Certain Gen5 chipsets require require idling the GPU before * unmapping anything from the GTT when VT-d is enabled. @@ -432,21 +429,16 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, enum i915_cache_level level) { struct drm_i915_private *dev_priv = dev->dev_private; - struct scatterlist *sg = st->sgl; - gtt_pte_t __iomem *gtt_entries = - (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; - int unused, i = 0; - unsigned int len, m = 0; + gen6_gtt_pte_t __iomem *gtt_entries = + (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; + int i = 0; + struct sg_page_iter sg_iter; dma_addr_t addr; - for_each_sg(st->sgl, sg, st->nents, unused) { - len = sg_dma_len(sg) >> PAGE_SHIFT; - for (m = 0; m < len; m++) { - addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - iowrite32(gen6_pte_encode(dev, addr, level), - >t_entries[i]); - i++; - } + for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { + addr = sg_page_iter_dma_address(&sg_iter); + iowrite32(gen6_pte_encode(dev, addr, level), >t_entries[i]); + i++; } /* XXX: This serves as a posting read to make sure that the PTE has @@ -472,8 +464,8 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, unsigned int num_entries) { struct drm_i915_private *dev_priv = dev->dev_private; - gtt_pte_t scratch_pte; - gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; + gen6_gtt_pte_t scratch_pte, __iomem *gtt_base = + (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; int i; @@ -647,9 +639,12 @@ void i915_gem_init_global_gtt(struct drm_device *dev) if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { int ret; - /* PPGTT pdes are stolen from global gtt ptes, so shrink the - * aperture accordingly when using aliasing ppgtt. */ - gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + + if (INTEL_INFO(dev)->gen <= 7) { + /* PPGTT pdes are stolen from global gtt ptes, so shrink the + * aperture accordingly when using aliasing ppgtt. */ + gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + } i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); @@ -752,15 +747,17 @@ static int gen6_gmch_probe(struct drm_device *dev, pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); - if (IS_GEN7(dev)) + if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) *stolen = gen7_get_stolen_size(snb_gmch_ctl); else *stolen = gen6_get_stolen_size(snb_gmch_ctl); - *gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; + *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT; + + /* For Modern GENs the PTEs and register space are split in the BAR */ + gtt_bus_addr = pci_resource_start(dev->pdev, 0) + + (pci_resource_len(dev->pdev, 0) / 2); - /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ - gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); if (!dev_priv->gtt.gsm) { DRM_ERROR("Failed to map the gtt page table\n"); @@ -817,7 +814,6 @@ int i915_gem_gtt_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_gtt *gtt = &dev_priv->gtt; - unsigned long gtt_size; int ret; if (INTEL_INFO(dev)->gen <= 5) { @@ -835,8 +831,6 @@ int i915_gem_gtt_init(struct drm_device *dev) if (ret) return ret; - gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); - /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %zdM\n", dev_priv->gtt.total >> 20); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 69d97cb..130d1db 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -312,6 +312,71 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) return NULL; } +struct drm_i915_gem_object * +i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, + u32 stolen_offset, + u32 gtt_offset, + u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + struct drm_mm_node *stolen; + + if (dev_priv->mm.stolen_base == 0) + return NULL; + + DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n", + stolen_offset, gtt_offset, size); + + /* KISS and expect everything to be page-aligned */ + BUG_ON(stolen_offset & 4095); + BUG_ON(gtt_offset & 4095); + BUG_ON(size & 4095); + + if (WARN_ON(size == 0)) + return NULL; + + stolen = drm_mm_create_block(&dev_priv->mm.stolen, + stolen_offset, size, + false); + if (stolen == NULL) { + DRM_DEBUG_KMS("failed to allocate stolen space\n"); + return NULL; + } + + obj = _i915_gem_object_create_stolen(dev, stolen); + if (obj == NULL) { + DRM_DEBUG_KMS("failed to allocate stolen object\n"); + drm_mm_put_block(stolen); + return NULL; + } + + /* To simplify the initialisation sequence between KMS and GTT, + * we allow construction of the stolen object prior to + * setting up the GTT space. The actual reservation will occur + * later. + */ + if (drm_mm_initialized(&dev_priv->mm.gtt_space)) { + obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space, + gtt_offset, size, + false); + if (obj->gtt_space == NULL) { + DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); + drm_gem_object_unreference(&obj->base); + return NULL; + } + } else + obj->gtt_space = I915_GTT_RESERVED; + + obj->gtt_offset = gtt_offset; + obj->has_global_gtt_mapping = 1; + + list_add_tail(&obj->gtt_list, &dev_priv->mm.bound_list); + list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + + return obj; +} + void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index abcba2f..537545b 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -217,9 +217,12 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) tile_width = 512; /* check maximum stride & object size */ - if (INTEL_INFO(dev)->gen >= 4) { - /* i965 stores the end address of the gtt mapping in the fence - * reg, so dont bother to check the size */ + /* i965+ stores the end address of the gtt mapping in the fence + * reg, so dont bother to check the size */ + if (INTEL_INFO(dev)->gen >= 7) { + if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL) + return false; + } else if (INTEL_INFO(dev)->gen >= 4) { if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) return false; } else { @@ -235,6 +238,9 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) } } + if (stride < tile_width) + return false; + /* 965+ just needs multiples of tile width */ if (INTEL_INFO(dev)->gen >= 4) { if (stride & (tile_width - 1)) @@ -243,9 +249,6 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) } /* Pre-965 needs power of two tile widths */ - if (stride < tile_width) - return false; - if (stride & (stride - 1)) return false; @@ -473,28 +476,29 @@ i915_gem_swizzle_page(struct page *page) void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) { - struct scatterlist *sg; - int page_count = obj->base.size >> PAGE_SHIFT; + struct sg_page_iter sg_iter; int i; if (obj->bit_17 == NULL) return; - for_each_sg(obj->pages->sgl, sg, page_count, i) { - struct page *page = sg_page(sg); + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_page_iter_page(&sg_iter); char new_bit_17 = page_to_phys(page) >> 17; if ((new_bit_17 & 0x1) != (test_bit(i, obj->bit_17) != 0)) { i915_gem_swizzle_page(page); set_page_dirty(page); } + i++; } } void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) { - struct scatterlist *sg; + struct sg_page_iter sg_iter; int page_count = obj->base.size >> PAGE_SHIFT; int i; @@ -508,11 +512,12 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) } } - for_each_sg(obj->pages->sgl, sg, page_count, i) { - struct page *page = sg_page(sg); - if (page_to_phys(page) & (1 << 17)) + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) __set_bit(i, obj->bit_17); else __clear_bit(i, obj->bit_17); + i++; } } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3c7bb04..0aa2ef0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -36,6 +36,61 @@ #include "i915_trace.h" #include "intel_drv.h" +static const u32 hpd_ibx[] = { + [HPD_CRT] = SDE_CRT_HOTPLUG, + [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, + [HPD_PORT_B] = SDE_PORTB_HOTPLUG, + [HPD_PORT_C] = SDE_PORTC_HOTPLUG, + [HPD_PORT_D] = SDE_PORTD_HOTPLUG +}; + +static const u32 hpd_cpt[] = { + [HPD_CRT] = SDE_CRT_HOTPLUG_CPT, + [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT, + [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, + [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, + [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT +}; + +static const u32 hpd_mask_i915[] = { + [HPD_CRT] = CRT_HOTPLUG_INT_EN, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN +}; + +static const u32 hpd_status_gen4[] = { + [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS +}; + +static const u32 hpd_status_i965[] = { + [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS +}; + +static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ + [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, + [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, + [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, + [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, + [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, + [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS +}; + +static void ibx_hpd_irq_setup(struct drm_device *dev); +static void i915_hpd_irq_setup(struct drm_device *dev); + /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) @@ -47,7 +102,7 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) } } -static inline void +static void ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->irq_mask & mask) != mask) { @@ -60,26 +115,30 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { - if ((dev_priv->pipestat[pipe] & mask) != mask) { - u32 reg = PIPESTAT(pipe); + u32 reg = PIPESTAT(pipe); + u32 pipestat = I915_READ(reg) & 0x7fff0000; - dev_priv->pipestat[pipe] |= mask; - /* Enable the interrupt, clear any pending status */ - I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); - POSTING_READ(reg); - } + if ((pipestat & mask) == mask) + return; + + /* Enable the interrupt, clear any pending status */ + pipestat |= mask | (mask >> 16); + I915_WRITE(reg, pipestat); + POSTING_READ(reg); } void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { - if ((dev_priv->pipestat[pipe] & mask) != 0) { - u32 reg = PIPESTAT(pipe); + u32 reg = PIPESTAT(pipe); + u32 pipestat = I915_READ(reg) & 0x7fff0000; - dev_priv->pipestat[pipe] &= ~mask; - I915_WRITE(reg, dev_priv->pipestat[pipe]); - POSTING_READ(reg); - } + if ((pipestat & mask) == 0) + return; + + pipestat &= ~mask; + I915_WRITE(reg, pipestat); + POSTING_READ(reg); } /** @@ -250,10 +309,9 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, struct timeval *vblank_time, unsigned flags) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; - if (pipe < 0 || pipe >= dev_priv->num_pipe) { + if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) { DRM_ERROR("Invalid crtc %d\n", pipe); return -EINVAL; } @@ -279,13 +337,19 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, /* * Handle hotplug events outside the interrupt handler proper. */ +#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) + static void i915_hotplug_work_func(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, hotplug_work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *encoder; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + unsigned long irqflags; + bool hpd_disabled = false; /* HPD irq before everything is fully set up. */ if (!dev_priv->enable_hotplug_processing) @@ -294,9 +358,36 @@ static void i915_hotplug_work_func(struct work_struct *work) mutex_lock(&mode_config->mutex); DRM_DEBUG_KMS("running encoder hotplug functions\n"); - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) - if (encoder->hot_plug) - encoder->hot_plug(encoder); + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + list_for_each_entry(connector, &mode_config->connector_list, head) { + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (intel_encoder->hpd_pin > HPD_NONE && + dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && + connector->polled == DRM_CONNECTOR_POLL_HPD) { + DRM_INFO("HPD interrupt storm detected on connector %s: " + "switching from hotplug detection to polling\n", + drm_get_connector_name(connector)); + dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; + connector->polled = DRM_CONNECTOR_POLL_CONNECT + | DRM_CONNECTOR_POLL_DISCONNECT; + hpd_disabled = true; + } + } + /* if there were no outputs to poll, poll was disabled, + * therefore make sure it's enabled when disabling HPD on + * some connectors */ + if (hpd_disabled) { + drm_kms_helper_poll_enable(dev); + mod_timer(&dev_priv->hotplug_reenable_timer, + jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); + } + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + if (intel_encoder->hot_plug) + intel_encoder->hot_plug(intel_encoder); mutex_unlock(&mode_config->mutex); @@ -525,6 +616,45 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, queue_work(dev_priv->wq, &dev_priv->rps.work); } +#define HPD_STORM_DETECT_PERIOD 1000 +#define HPD_STORM_THRESHOLD 5 + +static inline bool hotplug_irq_storm_detect(struct drm_device *dev, + u32 hotplug_trigger, + const u32 *hpd) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + int i; + bool ret = false; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + + for (i = 1; i < HPD_NUM_PINS; i++) { + + if (!(hpd[i] & hotplug_trigger) || + dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) + continue; + + if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, + dev_priv->hpd_stats[i].hpd_last_jiffies + + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { + dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; + dev_priv->hpd_stats[i].hpd_cnt = 0; + } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { + dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); + ret = true; + } else { + dev_priv->hpd_stats[i].hpd_cnt++; + } + } + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return ret; +} + static void gmbus_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -593,13 +723,16 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) /* Consume port. Then clear IIR or we'll miss events */ if (iir & I915_DISPLAY_PORT_INTERRUPT) { u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) + if (hotplug_trigger) { + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) + i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -623,10 +756,13 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; - if (pch_iir & SDE_HOTPLUG_MASK) + if (hotplug_trigger) { + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx)) + ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } if (pch_iir & SDE_AUDIO_POWER_MASK) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -669,10 +805,13 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - if (pch_iir & SDE_HOTPLUG_MASK_CPT) + if (hotplug_trigger) { + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt)) + ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> @@ -701,7 +840,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; + u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier = 0; irqreturn_t ret = IRQ_NONE; int i; @@ -716,9 +855,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) * able to process them after we restore SDEIER (as soon as we restore * it, we'll get an interrupt if SDEIIR still has something to process * due to its back queue). */ - sde_ier = I915_READ(SDEIER); - I915_WRITE(SDEIER, 0); - POSTING_READ(SDEIER); + if (!HAS_PCH_NOP(dev)) { + sde_ier = I915_READ(SDEIER); + I915_WRITE(SDEIER, 0); + POSTING_READ(SDEIER); + } gt_iir = I915_READ(GTIIR); if (gt_iir) { @@ -745,7 +886,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) } /* check event from PCH */ - if (de_iir & DE_PCH_EVENT_IVB) { + if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) { u32 pch_iir = I915_READ(SDEIIR); cpt_irq_handler(dev, pch_iir); @@ -768,8 +909,10 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); - I915_WRITE(SDEIER, sde_ier); - POSTING_READ(SDEIER); + if (!HAS_PCH_NOP(dev)) { + I915_WRITE(SDEIER, sde_ier); + POSTING_READ(SDEIER); + } return ret; } @@ -937,6 +1080,8 @@ static void i915_error_work_func(struct work_struct *work) for_each_ring(ring, dev_priv, i) wake_up_all(&ring->irq_queue); + intel_display_handle_reset(dev); + wake_up_all(&dev_priv->gpu_error.reset_queue); } } @@ -972,24 +1117,23 @@ static void i915_get_extra_instdone(struct drm_device *dev, #ifdef CONFIG_DEBUG_FS static struct drm_i915_error_object * -i915_error_object_create(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *src) +i915_error_object_create_sized(struct drm_i915_private *dev_priv, + struct drm_i915_gem_object *src, + const int num_pages) { struct drm_i915_error_object *dst; - int i, count; + int i; u32 reloc_offset; if (src == NULL || src->pages == NULL) return NULL; - count = src->base.size / PAGE_SIZE; - - dst = kmalloc(sizeof(*dst) + count * sizeof(u32 *), GFP_ATOMIC); + dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC); if (dst == NULL) return NULL; reloc_offset = src->gtt_offset; - for (i = 0; i < count; i++) { + for (i = 0; i < num_pages; i++) { unsigned long flags; void *d; @@ -1039,7 +1183,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, reloc_offset += PAGE_SIZE; } - dst->page_count = count; + dst->page_count = num_pages; dst->gtt_offset = src->gtt_offset; return dst; @@ -1050,6 +1194,9 @@ unwind: kfree(dst); return NULL; } +#define i915_error_object_create(dev_priv, src) \ + i915_error_object_create_sized((dev_priv), (src), \ + (src)->base.size>>PAGE_SHIFT) static void i915_error_object_free(struct drm_i915_error_object *obj) @@ -1148,7 +1295,7 @@ static void i915_gem_record_fences(struct drm_device *dev, switch (INTEL_INFO(dev)->gen) { case 7: case 6: - for (i = 0; i < 16; i++) + for (i = 0; i < dev_priv->num_fence_regs; i++) error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); break; case 5: @@ -1256,6 +1403,26 @@ static void i915_record_ring_state(struct drm_device *dev, error->cpu_ring_tail[ring->id] = ring->tail; } + +static void i915_gem_record_active_context(struct intel_ring_buffer *ring, + struct drm_i915_error_state *error, + struct drm_i915_error_ring *ering) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_object *obj; + + /* Currently render ring is the only HW context user */ + if (ring->id != RCS || !error->ccid) + return; + + list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + if ((error->ccid & PAGE_MASK) == obj->gtt_offset) { + ering->ctx = i915_error_object_create_sized(dev_priv, + obj, 1); + } + } +} + static void i915_gem_record_rings(struct drm_device *dev, struct drm_i915_error_state *error) { @@ -1273,6 +1440,9 @@ static void i915_gem_record_rings(struct drm_device *dev, error->ring[i].ringbuffer = i915_error_object_create(dev_priv, ring->obj); + + i915_gem_record_active_context(ring, error, &error->ring[i]); + count = 0; list_for_each_entry(request, &ring->request_list, list) count++; @@ -1328,14 +1498,15 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("capturing error event; look for more information in" + DRM_INFO("capturing error event; look for more information in " "/sys/kernel/debug/dri/%d/i915_error_state\n", dev->primary->index); kref_init(&error->ref); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); - error->ccid = I915_READ(CCID); + if (HAS_HW_CONTEXTS(dev)) + error->ccid = I915_READ(CCID); if (HAS_PCH_SPLIT(dev)) error->ier = I915_READ(DEIER) | I915_READ(GTIER); @@ -1356,8 +1527,9 @@ static void i915_capture_error_state(struct drm_device *dev) else if (INTEL_INFO(dev)->gen == 6) error->forcewake = I915_READ(FORCEWAKE); - for_each_pipe(pipe) - error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); + if (!HAS_PCH_SPLIT(dev)) + for_each_pipe(pipe) + error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); if (INTEL_INFO(dev)->gen >= 6) { error->error = I915_READ(ERROR_GEN6); @@ -1567,7 +1739,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged) queue_work(dev_priv->wq, &dev_priv->gpu_error.work); } -static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) +static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; @@ -1777,6 +1949,37 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) return false; } +static bool semaphore_passed(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; + struct intel_ring_buffer *signaller; + u32 cmd, ipehr, acthd_min; + + ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); + if ((ipehr & ~(0x3 << 16)) != + (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) + return false; + + /* ACTHD is likely pointing to the dword after the actual command, + * so scan backwards until we find the MBOX. + */ + acthd_min = max((int)acthd - 3 * 4, 0); + do { + cmd = ioread32(ring->virtual_start + acthd); + if (cmd == ipehr) + break; + + acthd -= 4; + if (acthd < acthd_min) + return false; + } while (1); + + signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; + return i915_seqno_passed(signaller->get_seqno(signaller, false), + ioread32(ring->virtual_start+acthd+4)+1); +} + static bool kick_ring(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -1788,6 +1991,15 @@ static bool kick_ring(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, tmp); return true; } + + if (INTEL_INFO(dev)->gen >= 6 && + tmp & RING_WAIT_SEMAPHORE && + semaphore_passed(ring)) { + DRM_ERROR("Kicking stuck semaphore on %s\n", + ring->name); + I915_WRITE_CTL(ring, tmp); + return true; + } return false; } @@ -1901,9 +2113,18 @@ static void ironlake_irq_preinstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); POSTING_READ(GTIER); + if (HAS_PCH_NOP(dev)) + return; + /* south display irq */ I915_WRITE(SDEIMR, 0xffffffff); - I915_WRITE(SDEIER, 0x0); + /* + * SDEIER is also touched by the interrupt handler to work around missed + * PCH interrupts. Hence we can't update it after the interrupt handler + * is enabled - instead we unconditionally enable all PCH interrupt + * sources here, but then only unmask them as needed with SDEIMR. + */ + I915_WRITE(SDEIER, 0xffffffff); POSTING_READ(SDEIER); } @@ -1939,18 +2160,34 @@ static void valleyview_irq_preinstall(struct drm_device *dev) POSTING_READ(VLV_IER); } -/* - * Enable digital hotplug on the PCH, and configure the DP short pulse - * duration to 2ms (which is the minimum in the Display Port spec) - * - * This register is the same on all known PCH chips. - */ - -static void ibx_enable_hotplug(struct drm_device *dev) +static void ibx_hpd_irq_setup(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *intel_encoder; + u32 mask = ~I915_READ(SDEIMR); + u32 hotplug; + + if (HAS_PCH_IBX(dev)) { + mask &= ~SDE_HOTPLUG_MASK; + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + mask |= hpd_ibx[intel_encoder->hpd_pin]; + } else { + mask &= ~SDE_HOTPLUG_MASK_CPT; + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + mask |= hpd_cpt[intel_encoder->hpd_pin]; + } + I915_WRITE(SDEIMR, ~mask); + + /* + * Enable digital hotplug on the PCH, and configure the DP short pulse + * duration to 2ms (which is the minimum in the Display Port spec) + * + * This register is the same on all known PCH chips. + */ hotplug = I915_READ(PCH_PORT_HOTPLUG); hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK); hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms; @@ -1965,20 +2202,15 @@ static void ibx_irq_postinstall(struct drm_device *dev) u32 mask; if (HAS_PCH_IBX(dev)) - mask = SDE_HOTPLUG_MASK | - SDE_GMBUS | - SDE_AUX_MASK; + mask = SDE_GMBUS | SDE_AUX_MASK; else - mask = SDE_HOTPLUG_MASK_CPT | - SDE_GMBUS_CPT | - SDE_AUX_MASK_CPT; + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; + + if (HAS_PCH_NOP(dev)) + return; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, ~mask); - I915_WRITE(SDEIER, mask); - POSTING_READ(SDEIER); - - ibx_enable_hotplug(dev); } static int ironlake_irq_postinstall(struct drm_device *dev) @@ -2089,9 +2321,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; - /* Hack for broken MSIs on VLV */ pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000); pci_read_config_word(dev->pdev, 0x98, &msid); @@ -2135,30 +2364,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) return 0; } -static void valleyview_hpd_irq_setup(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); - - /* Note HDMI and DP share bits */ - if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) - hotplug_en |= PORTB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) - hotplug_en |= PORTC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) - hotplug_en |= PORTD_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { - hotplug_en |= CRT_HOTPLUG_INT_EN; - hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - } - - I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); -} - static void valleyview_irq_uninstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -2167,6 +2372,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + for_each_pipe(pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); @@ -2188,6 +2395,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(DEIMR, 0xffffffff); @@ -2198,6 +2407,9 @@ static void ironlake_irq_uninstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); I915_WRITE(GTIIR, I915_READ(GTIIR)); + if (HAS_PCH_NOP(dev)) + return; + I915_WRITE(SDEIMR, 0xffffffff); I915_WRITE(SDEIER, 0x0); I915_WRITE(SDEIIR, I915_READ(SDEIIR)); @@ -2221,9 +2433,6 @@ static int i8xx_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; - I915_WRITE16(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); @@ -2246,6 +2455,37 @@ static int i8xx_irq_postinstall(struct drm_device *dev) return 0; } +/* + * Returns true when a page flip has completed. + */ +static bool i8xx_handle_vblank(struct drm_device *dev, + int pipe, u16 iir) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); + + if (!drm_handle_vblank(dev, pipe)) + return false; + + if ((iir & flip_pending) == 0) + return false; + + intel_prepare_page_flip(dev, pipe); + + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise + * an interrupt per se, we watch for the change at vblank. + */ + if (I915_READ16(ISR) & flip_pending) + return false; + + intel_finish_page_flip(dev, pipe); + + return true; +} + static irqreturn_t i8xx_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -2301,22 +2541,12 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) notify_ring(dev, &dev_priv->ring[RCS]); if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, 0)) { - if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { - intel_prepare_page_flip(dev, 0); - intel_finish_page_flip(dev, 0); - flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; - } - } + i8xx_handle_vblank(dev, 0, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0); if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, 1)) { - if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) { - intel_prepare_page_flip(dev, 1); - intel_finish_page_flip(dev, 1); - flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; - } - } + i8xx_handle_vblank(dev, 1, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1); iir = new_iir; } @@ -2364,9 +2594,6 @@ static int i915_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; - I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH)); /* Unmask the interrupts that we always want on. */ @@ -2404,33 +2631,35 @@ static int i915_irq_postinstall(struct drm_device *dev) return 0; } -static void i915_hpd_irq_setup(struct drm_device *dev) +/* + * Returns true when a page flip has completed. + */ +static bool i915_handle_vblank(struct drm_device *dev, + int plane, int pipe, u32 iir) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug_en; + drm_i915_private_t *dev_priv = dev->dev_private; + u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); - if (I915_HAS_HOTPLUG(dev)) { - hotplug_en = I915_READ(PORT_HOTPLUG_EN); + if (!drm_handle_vblank(dev, pipe)) + return false; - if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) - hotplug_en |= PORTB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) - hotplug_en |= PORTC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) - hotplug_en |= PORTD_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { - hotplug_en |= CRT_HOTPLUG_INT_EN; - hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - } + if ((iir & flip_pending) == 0) + return false; - /* Ignore TV since it's buggy */ + intel_prepare_page_flip(dev, plane); - I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - } + /* We detect FlipDone by looking for the change in PendingFlip from '1' + * to '0' on the following vblank, i.e. IIR has the Pendingflip + * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence + * the flip is completed (no longer pending). Since this doesn't raise + * an interrupt per se, we watch for the change at vblank. + */ + if (I915_READ(ISR) & flip_pending) + return false; + + intel_finish_page_flip(dev, pipe); + + return true; } static irqreturn_t i915_irq_handler(int irq, void *arg) @@ -2442,10 +2671,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) u32 flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; - u32 flip[2] = { - I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT, - I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT - }; int pipe, ret = IRQ_NONE; atomic_inc(&dev_priv->irq_received); @@ -2486,13 +2711,16 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) if ((I915_HAS_HOTPLUG(dev)) && (iir & I915_DISPLAY_PORT_INTERRUPT)) { u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) + if (hotplug_trigger) { + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) + i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); POSTING_READ(PORT_HOTPLUG_STAT); } @@ -2507,14 +2735,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) int plane = pipe; if (IS_MOBILE(dev)) plane = !plane; + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, pipe)) { - if (iir & flip[plane]) { - intel_prepare_page_flip(dev, plane); - intel_finish_page_flip(dev, pipe); - flip_mask &= ~flip[plane]; - } - } + i915_handle_vblank(dev, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; @@ -2552,6 +2776,8 @@ static void i915_irq_uninstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -2603,13 +2829,13 @@ static int i965_irq_postinstall(struct drm_device *dev) I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); enable_mask = ~dev_priv->irq_mask; + enable_mask &= ~(I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT); enable_mask |= I915_USER_INTERRUPT; if (IS_G4X(dev)) enable_mask |= I915_BSD_USER_INTERRUPT; - dev_priv->pipestat[0] = 0; - dev_priv->pipestat[1] = 0; i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); /* @@ -2639,45 +2865,33 @@ static int i965_irq_postinstall(struct drm_device *dev) return 0; } -static void i965_hpd_irq_setup(struct drm_device *dev) +static void i915_hpd_irq_setup(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *intel_encoder; u32 hotplug_en; - /* Note HDMI and DP share hotplug bits */ - hotplug_en = 0; - if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) - hotplug_en |= PORTB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) - hotplug_en |= PORTC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) - hotplug_en |= PORTD_HOTPLUG_INT_EN; - if (IS_G4X(dev)) { - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_G4X) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - } else { - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I965) - hotplug_en |= SDVOC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I965) - hotplug_en |= SDVOB_HOTPLUG_INT_EN; - } - if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) { - hotplug_en |= CRT_HOTPLUG_INT_EN; - + if (I915_HAS_HOTPLUG(dev)) { + hotplug_en = I915_READ(PORT_HOTPLUG_EN); + hotplug_en &= ~HOTPLUG_INT_EN_MASK; + /* Note HDMI and DP share hotplug bits */ + /* enable bits are the same for all generations */ + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; /* Programming the CRT detection parameters tends to generate a spurious hotplug event about three seconds later. So just do it once. - */ + */ if (IS_G4X(dev)) hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; + hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - } - - /* Ignore TV since it's buggy */ - I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); + /* Ignore TV since it's buggy */ + I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); + } } static irqreturn_t i965_irq_handler(int irq, void *arg) @@ -2689,6 +2903,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) unsigned long irqflags; int irq_received; int ret = IRQ_NONE, pipe; + u32 flip_mask = + I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | + I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; atomic_inc(&dev_priv->irq_received); @@ -2697,7 +2914,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) for (;;) { bool blc_event = false; - irq_received = iir != 0; + irq_received = (iir & ~flip_mask) != 0; /* Can't rely on pipestat interrupt bit in iir as it might * have been cleared after the pipestat interrupt was received. @@ -2733,18 +2950,24 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) /* Consume port. Then clear IIR or we'll miss events */ if (iir & I915_DISPLAY_PORT_INTERRUPT) { u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? + HOTPLUG_INT_STATUS_G4X : + HOTPLUG_INT_STATUS_I965); DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & dev_priv->hotplug_supported_mask) + if (hotplug_trigger) { + if (hotplug_irq_storm_detect(dev, hotplug_trigger, + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965)) + i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } - I915_WRITE(IIR, iir); + I915_WRITE(IIR, iir & ~flip_mask); new_iir = I915_READ(IIR); /* Flush posted writes */ if (iir & I915_USER_INTERRUPT) @@ -2752,18 +2975,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) if (iir & I915_BSD_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); - if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) - intel_prepare_page_flip(dev, 0); - - if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) - intel_prepare_page_flip(dev, 1); - for_each_pipe(pipe) { if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS && - drm_handle_vblank(dev, pipe)) { - i915_pageflip_stall_check(dev, pipe); - intel_finish_page_flip(dev, pipe); - } + i915_handle_vblank(dev, pipe, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; @@ -2807,6 +3022,8 @@ static void i965_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -2822,6 +3039,41 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } +static void i915_reenable_hotplug_timer_func(unsigned long data) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + unsigned long irqflags; + int i; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { + struct drm_connector *connector; + + if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED) + continue; + + dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + + if (intel_connector->encoder->hpd_pin == i) { + if (connector->polled != intel_connector->polled) + DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", + drm_get_connector_name(connector)); + connector->polled = intel_connector->polled; + if (!connector->polled) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + } + } + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + void intel_irq_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2834,6 +3086,8 @@ void intel_irq_init(struct drm_device *dev) setup_timer(&dev_priv->gpu_error.hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); + setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, + (unsigned long) dev_priv); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); @@ -2857,7 +3111,7 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = valleyview_irq_uninstall; dev->driver->enable_vblank = valleyview_enable_vblank; dev->driver->disable_vblank = valleyview_disable_vblank; - dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup; + dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { /* Share pre & uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; @@ -2866,6 +3120,7 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2873,6 +3128,7 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ironlake_enable_vblank; dev->driver->disable_vblank = ironlake_disable_vblank; + dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup; } else { if (INTEL_INFO(dev)->gen == 2) { dev->driver->irq_preinstall = i8xx_irq_preinstall; @@ -2890,7 +3146,7 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_postinstall = i965_irq_postinstall; dev->driver->irq_uninstall = i965_irq_uninstall; dev->driver->irq_handler = i965_irq_handler; - dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup; + dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } dev->driver->enable_vblank = i915_enable_vblank; dev->driver->disable_vblank = i915_disable_vblank; @@ -2900,7 +3156,20 @@ void intel_irq_init(struct drm_device *dev) void intel_hpd_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + int i; + for (i = 1; i < HPD_NUM_PINS; i++) { + dev_priv->hpd_stats[i].hpd_cnt = 0; + dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + } + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + connector->polled = intel_connector->polled; + if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 848992f..83f9c26 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -91,6 +91,7 @@ #define GRDOM_FULL (0<<2) #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) +#define GRDOM_MASK (3<<2) #define GRDOM_RESET_ENABLE (1<<0) #define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ @@ -121,10 +122,17 @@ #define GAM_ECOCHK 0x4090 #define ECOCHK_SNB_BIT (1<<10) +#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) +#define ECOCHK_PPGTT_GFDT_IVB (0x1<<4) +#define ECOCHK_PPGTT_LLC_IVB (0x1<<3) +#define ECOCHK_PPGTT_UC_HSW (0x1<<3) +#define ECOCHK_PPGTT_WT_HSW (0x2<<3) +#define ECOCHK_PPGTT_WB_HSW (0x3<<3) #define GAC_ECO_BITS 0x14090 +#define ECOBITS_SNB_BIT (1<<13) #define ECOBITS_PPGTT_CACHE64B (3<<8) #define ECOBITS_PPGTT_CACHE4B (0<<8) @@ -422,6 +430,7 @@ #define FENCE_REG_SANDYBRIDGE_0 0x100000 #define SANDYBRIDGE_FENCE_PITCH_SHIFT 32 +#define GEN7_FENCE_MAX_PITCH_VAL 0x0800 /* control register for cpu gtt access */ #define TILECTL 0x101000 @@ -522,6 +531,9 @@ #define GEN7_ERR_INT 0x44040 #define ERR_INT_MMIO_UNCLAIMED (1<<13) +#define FPGA_DBG 0x42300 +#define FPGA_DBG_RM_NOCLAIM (1<<31) + #define DERRMR 0x44050 /* GM45+ chicken bits -- debug workaround bits that may be required @@ -591,6 +603,7 @@ #define I915_USER_INTERRUPT (1<<1) #define I915_ASLE_INTERRUPT (1<<0) #define I915_BSD_USER_INTERRUPT (1<<25) +#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ #define EIR 0x020b0 #define EMR 0x020b4 #define ESR 0x020b8 @@ -1197,6 +1210,9 @@ #define MCHBAR_MIRROR_BASE_SNB 0x140000 +/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ +#define DCLK 0x5e04 + /** 915-945 and GM965 MCH register controlling DRAM channel access */ #define DCC 0x10200 #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) @@ -1637,6 +1653,12 @@ #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) #define CRT_HOTPLUG_INT_EN (1 << 9) +#define HOTPLUG_INT_EN_MASK (PORTB_HOTPLUG_INT_EN | \ + PORTC_HOTPLUG_INT_EN | \ + PORTD_HOTPLUG_INT_EN | \ + SDVOC_HOTPLUG_INT_EN | \ + SDVOB_HOTPLUG_INT_EN | \ + CRT_HOTPLUG_INT_EN) #define CRT_HOTPLUG_FORCE_DETECT (1 << 3) #define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8) /* must use period 64 on GM45 according to docs */ @@ -1675,43 +1697,84 @@ #define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) #define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) #define SDVOB_HOTPLUG_INT_STATUS_I915 (1 << 6) - -/* SDVO port control */ -#define SDVOB 0x61140 -#define SDVOC 0x61160 -#define SDVO_ENABLE (1 << 31) -#define SDVO_PIPE_B_SELECT (1 << 30) -#define SDVO_STALL_SELECT (1 << 29) -#define SDVO_INTERRUPT_ENABLE (1 << 26) +#define HOTPLUG_INT_STATUS_G4X (CRT_HOTPLUG_INT_STATUS | \ + SDVOB_HOTPLUG_INT_STATUS_G4X | \ + SDVOC_HOTPLUG_INT_STATUS_G4X | \ + PORTB_HOTPLUG_INT_STATUS | \ + PORTC_HOTPLUG_INT_STATUS | \ + PORTD_HOTPLUG_INT_STATUS) + +#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \ + SDVOB_HOTPLUG_INT_STATUS_I965 | \ + SDVOC_HOTPLUG_INT_STATUS_I965 | \ + PORTB_HOTPLUG_INT_STATUS | \ + PORTC_HOTPLUG_INT_STATUS | \ + PORTD_HOTPLUG_INT_STATUS) + +#define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \ + SDVOB_HOTPLUG_INT_STATUS_I915 | \ + SDVOC_HOTPLUG_INT_STATUS_I915 | \ + PORTB_HOTPLUG_INT_STATUS | \ + PORTC_HOTPLUG_INT_STATUS | \ + PORTD_HOTPLUG_INT_STATUS) + +/* SDVO and HDMI port control. + * The same register may be used for SDVO or HDMI */ +#define GEN3_SDVOB 0x61140 +#define GEN3_SDVOC 0x61160 +#define GEN4_HDMIB GEN3_SDVOB +#define GEN4_HDMIC GEN3_SDVOC +#define PCH_SDVOB 0xe1140 +#define PCH_HDMIB PCH_SDVOB +#define PCH_HDMIC 0xe1150 +#define PCH_HDMID 0xe1160 + +/* Gen 3 SDVO bits: */ +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_SEL(pipe) ((pipe) << 30) +#define SDVO_PIPE_SEL_MASK (1 << 30) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) /** * 915G/GM SDVO pixel multiplier. - * * Programmed value is multiplier - 1, up to 5x. - * * \sa DPLL_MD_UDI_MULTIPLIER_MASK */ -#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) #define SDVO_PORT_MULTIPLY_SHIFT 23 -#define SDVO_PHASE_SELECT_MASK (15 << 19) -#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) -#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) -#define SDVOC_GANG_MODE (1 << 16) -#define SDVO_ENCODING_SDVO (0x0 << 10) -#define SDVO_ENCODING_HDMI (0x2 << 10) -/** Requird for HDMI operation */ -#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) -#define SDVO_COLOR_RANGE_16_235 (1 << 8) -#define SDVO_BORDER_ENABLE (1 << 7) -#define SDVO_AUDIO_ENABLE (1 << 6) -/** New with 965, default is to be set */ -#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) -/** New with 965, default is to be set */ -#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) -#define SDVOB_PCIE_CONCURRENCY (1 << 3) -#define SDVO_DETECTED (1 << 2) +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) /* Port C only */ +#define SDVO_BORDER_ENABLE (1 << 7) /* SDVO only */ +#define SDVOB_PCIE_CONCURRENCY (1 << 3) /* Port B only */ +#define SDVO_DETECTED (1 << 2) /* Bits to be preserved when writing */ -#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) -#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \ + SDVO_INTERRUPT_ENABLE) +#define SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE) + +/* Gen 4 SDVO/HDMI bits: */ +#define SDVO_COLOR_FORMAT_8bpc (0 << 26) +#define SDVO_ENCODING_SDVO (0 << 10) +#define SDVO_ENCODING_HDMI (2 << 10) +#define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ +#define HDMI_MODE_SELECT_DVI (0 << 9) /* HDMI only */ +#define HDMI_COLOR_RANGE_16_235 (1 << 8) /* HDMI only */ +#define SDVO_AUDIO_ENABLE (1 << 6) +/* VSYNC/HSYNC bits new with 965, default is to be set */ +#define SDVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define SDVO_HSYNC_ACTIVE_HIGH (1 << 3) + +/* Gen 5 (IBX) SDVO/HDMI bits: */ +#define HDMI_COLOR_FORMAT_12bpc (3 << 26) /* HDMI only */ +#define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ + +/* Gen 6 (CPT) SDVO/HDMI bits: */ +#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29) +#define SDVO_PIPE_SEL_MASK_CPT (3 << 29) + /* DVO port control */ #define DVOA 0x61120 @@ -1898,7 +1961,7 @@ #define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) /* Backlight control */ -#define BLC_PWM_CTL2 0x61250 /* 965+ only */ +#define BLC_PWM_CTL2 (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */ #define BLM_PWM_ENABLE (1 << 31) #define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */ #define BLM_PIPE_SELECT (1 << 29) @@ -1917,7 +1980,7 @@ #define BLM_PHASE_IN_COUNT_MASK (0xff << 8) #define BLM_PHASE_IN_INCR_SHIFT (0) #define BLM_PHASE_IN_INCR_MASK (0xff << 0) -#define BLC_PWM_CTL 0x61254 +#define BLC_PWM_CTL (dev_priv->info->display_mmio_offset + 0x61254) /* * This is the most significant 15 bits of the number of backlight cycles in a * complete cycle of the modulated backlight control. @@ -1939,7 +2002,7 @@ #define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe) #define BLM_POLARITY_PNV (1 << 0) /* pnv only */ -#define BLC_HIST_CTL 0x61260 +#define BLC_HIST_CTL (dev_priv->info->display_mmio_offset + 0x61260) /* New registers for PCH-split platforms. Safe where new bits show up, the * register layout machtes with gen4 BLC_PWM_CTL[12]. */ @@ -2589,14 +2652,14 @@ #define _PIPEB_GMCH_DATA_M 0x71050 /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ -#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) -#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 +#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE_MASK (0x3f << 25) -#define PIPE_GMCH_DATA_M_MASK (0xffffff) +#define DATA_LINK_M_N_MASK (0xffffff) +#define DATA_LINK_N_MAX (0x800000) #define _PIPEA_GMCH_DATA_N 0x70054 #define _PIPEB_GMCH_DATA_N 0x71054 -#define PIPE_GMCH_DATA_N_MASK (0xffffff) /* * Computing Link M and N values for the Display Port link @@ -2611,11 +2674,9 @@ #define _PIPEA_DP_LINK_M 0x70060 #define _PIPEB_DP_LINK_M 0x71060 -#define PIPEA_DP_LINK_M_MASK (0xffffff) #define _PIPEA_DP_LINK_N 0x70064 #define _PIPEB_DP_LINK_N 0x71064 -#define PIPEA_DP_LINK_N_MASK (0xffffff) #define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) #define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) @@ -2776,6 +2837,8 @@ #define DSPFW_HPLL_CURSOR_SHIFT 16 #define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) #define DSPFW_HPLL_SR_MASK (0x1ff) +#define DSPFW4 (dev_priv->info->display_mmio_offset + 0x70070) +#define DSPFW7 (dev_priv->info->display_mmio_offset + 0x7007c) /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 @@ -3233,6 +3296,63 @@ #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) +#define _SPACNTR 0x72180 +#define SP_ENABLE (1<<31) +#define SP_GEAMMA_ENABLE (1<<30) +#define SP_PIXFORMAT_MASK (0xf<<26) +#define SP_FORMAT_YUV422 (0<<26) +#define SP_FORMAT_BGR565 (5<<26) +#define SP_FORMAT_BGRX8888 (6<<26) +#define SP_FORMAT_BGRA8888 (7<<26) +#define SP_FORMAT_RGBX1010102 (8<<26) +#define SP_FORMAT_RGBA1010102 (9<<26) +#define SP_FORMAT_RGBX8888 (0xe<<26) +#define SP_FORMAT_RGBA8888 (0xf<<26) +#define SP_SOURCE_KEY (1<<22) +#define SP_YUV_BYTE_ORDER_MASK (3<<16) +#define SP_YUV_ORDER_YUYV (0<<16) +#define SP_YUV_ORDER_UYVY (1<<16) +#define SP_YUV_ORDER_YVYU (2<<16) +#define SP_YUV_ORDER_VYUY (3<<16) +#define SP_TILED (1<<10) +#define _SPALINOFF 0x72184 +#define _SPASTRIDE 0x72188 +#define _SPAPOS 0x7218c +#define _SPASIZE 0x72190 +#define _SPAKEYMINVAL 0x72194 +#define _SPAKEYMSK 0x72198 +#define _SPASURF 0x7219c +#define _SPAKEYMAXVAL 0x721a0 +#define _SPATILEOFF 0x721a4 +#define _SPACONSTALPHA 0x721a8 +#define _SPAGAMC 0x721f4 + +#define _SPBCNTR 0x72280 +#define _SPBLINOFF 0x72284 +#define _SPBSTRIDE 0x72288 +#define _SPBPOS 0x7228c +#define _SPBSIZE 0x72290 +#define _SPBKEYMINVAL 0x72294 +#define _SPBKEYMSK 0x72298 +#define _SPBSURF 0x7229c +#define _SPBKEYMAXVAL 0x722a0 +#define _SPBTILEOFF 0x722a4 +#define _SPBCONSTALPHA 0x722a8 +#define _SPBGAMC 0x722f4 + +#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) +#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) +#define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE) +#define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS) +#define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE) +#define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL) +#define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK) +#define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF) +#define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL) +#define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF) +#define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA) +#define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC) + /* VBIOS regs */ #define VGACNTRL 0x71400 # define VGA_DISP_DISABLE (1 << 31) @@ -3282,8 +3402,6 @@ #define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) -#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ -#define TU_SIZE_MASK 0x7e000000 #define PIPE_DATA_M1_OFFSET 0 #define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) #define PIPE_DATA_N1_OFFSET 0 @@ -3456,6 +3574,9 @@ #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) +#define GEN7_MSG_CTL 0x45010 +#define WAIT_FOR_PCH_RESET_ACK (1<<1) +#define WAIT_FOR_PCH_FLR_ACK (1<<0) /* GEN7 chicken */ #define GEN7_COMMON_SLICE_CHICKEN1 0x7010 @@ -3508,7 +3629,11 @@ #define SDE_PORTC_HOTPLUG (1 << 9) #define SDE_PORTB_HOTPLUG (1 << 8) #define SDE_SDVOB_HOTPLUG (1 << 6) -#define SDE_HOTPLUG_MASK (0xf << 8) +#define SDE_HOTPLUG_MASK (SDE_CRT_HOTPLUG | \ + SDE_SDVOB_HOTPLUG | \ + SDE_PORTB_HOTPLUG | \ + SDE_PORTC_HOTPLUG | \ + SDE_PORTD_HOTPLUG) #define SDE_TRANSB_CRC_DONE (1 << 5) #define SDE_TRANSB_CRC_ERR (1 << 4) #define SDE_TRANSB_FIFO_UNDER (1 << 3) @@ -3531,7 +3656,9 @@ #define SDE_PORTC_HOTPLUG_CPT (1 << 22) #define SDE_PORTB_HOTPLUG_CPT (1 << 21) #define SDE_CRT_HOTPLUG_CPT (1 << 19) +#define SDE_SDVOB_HOTPLUG_CPT (1 << 18) #define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \ + SDE_SDVOB_HOTPLUG_CPT | \ SDE_PORTD_HOTPLUG_CPT | \ SDE_PORTC_HOTPLUG_CPT | \ SDE_PORTB_HOTPLUG_CPT) @@ -3754,14 +3881,16 @@ #define HSW_VIDEO_DIP_VSC_ECC_B 0x61344 #define HSW_VIDEO_DIP_GCP_B 0x61210 -#define HSW_TVIDEO_DIP_CTL(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) -#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) -#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) -#define HSW_TVIDEO_DIP_GCP(pipe) \ - _PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) +#define HSW_TVIDEO_DIP_CTL(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) +#define HSW_TVIDEO_DIP_AVI_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) +#define HSW_TVIDEO_DIP_SPD_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) +#define HSW_TVIDEO_DIP_GCP(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) +#define HSW_TVIDEO_DIP_VSC_DATA(trans) \ + _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) #define _TRANS_HTOTAL_B 0xe1000 #define _TRANS_HBLANK_B 0xe1004 @@ -3826,8 +3955,11 @@ #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) -#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) - +#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) +#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) +#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25) #define SOUTH_CHICKEN1 0xc2000 #define FDIA_PHASE_SYNC_SHIFT_OVR 19 @@ -3976,34 +4108,6 @@ #define FDI_PLL_CTL_1 0xfe000 #define FDI_PLL_CTL_2 0xfe004 -/* or SDVOB */ -#define HDMIB 0xe1140 -#define PORT_ENABLE (1 << 31) -#define TRANSCODER(pipe) ((pipe) << 30) -#define TRANSCODER_CPT(pipe) ((pipe) << 29) -#define TRANSCODER_MASK (1 << 30) -#define TRANSCODER_MASK_CPT (3 << 29) -#define COLOR_FORMAT_8bpc (0) -#define COLOR_FORMAT_12bpc (3 << 26) -#define SDVOB_HOTPLUG_ENABLE (1 << 23) -#define SDVO_ENCODING (0) -#define TMDS_ENCODING (2 << 10) -#define NULL_PACKET_VSYNC_ENABLE (1 << 9) -/* CPT */ -#define HDMI_MODE_SELECT (1 << 9) -#define DVI_MODE_SELECT (0) -#define SDVOB_BORDER_ENABLE (1 << 7) -#define AUDIO_ENABLE (1 << 6) -#define VSYNC_ACTIVE_HIGH (1 << 4) -#define HSYNC_ACTIVE_HIGH (1 << 3) -#define PORT_DETECTED (1 << 2) - -/* PCH SDVOB multiplex with HDMIB */ -#define PCH_SDVOB HDMIB - -#define HDMIC 0xe1150 -#define HDMID 0xe1160 - #define PCH_LVDS 0xe1180 #define LVDS_DETECTED (1 << 1) @@ -4020,6 +4124,15 @@ #define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) #define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) +#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS) +#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL) +#define VLV_PIPE_PP_ON_DELAYS(pipe) \ + _PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS) +#define VLV_PIPE_PP_OFF_DELAYS(pipe) \ + _PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS) +#define VLV_PIPE_PP_DIVISOR(pipe) \ + _PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR) + #define PCH_PP_STATUS 0xc7200 #define PCH_PP_CONTROL 0xc7204 #define PANEL_UNLOCK_REGS (0xabcd << 16) @@ -4149,8 +4262,12 @@ #define FORCEWAKE 0xA18C #define FORCEWAKE_VLV 0x1300b0 #define FORCEWAKE_ACK_VLV 0x1300b4 +#define FORCEWAKE_MEDIA_VLV 0x1300b8 +#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc #define FORCEWAKE_ACK_HSW 0x130044 #define FORCEWAKE_ACK 0x130090 +#define VLV_GTLC_WAKE_CTRL 0x130090 +#define VLV_GTLC_PW_STATUS 0x130094 #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 @@ -4184,6 +4301,7 @@ #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) +#define HSW_FREQUENCY(x) ((x)<<24) #define GEN6_OFFSET(x) ((x)<<19) #define GEN6_AGGRESSIVE_TURBO (0<<15) #define GEN6_RC_VIDEO_FREQ 0xA00C @@ -4274,6 +4392,21 @@ #define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) #define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 +#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 + +#define VLV_IOSF_DOORBELL_REQ 0x182100 +#define IOSF_DEVFN_SHIFT 24 +#define IOSF_OPCODE_SHIFT 16 +#define IOSF_PORT_SHIFT 8 +#define IOSF_BYTE_ENABLES_SHIFT 4 +#define IOSF_BAR_SHIFT 1 +#define IOSF_SB_BUSY (1<<0) +#define IOSF_PORT_PUNIT 0x4 +#define VLV_IOSF_DATA 0x182104 +#define VLV_IOSF_ADDR 0x182108 + +#define PUNIT_OPCODE_REG_READ 6 +#define PUNIT_OPCODE_REG_WRITE 7 #define GEN6_GT_CORE_STATUS 0x138060 #define GEN6_CORE_CPD_STATE_MASK (7<<4) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 2135f21..41f0fde 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -209,7 +209,8 @@ static void i915_save_display(struct drm_device *dev) 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); - dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); } else { dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); @@ -255,6 +256,7 @@ static void i915_save_display(struct drm_device *dev) static void i915_restore_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 mask = 0xffffffff; /* Display arbitration */ if (INTEL_INFO(dev)->gen <= 4) @@ -267,10 +269,13 @@ static void i915_restore_display(struct drm_device *dev) if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS); - } else if (IS_MOBILE(dev) && !IS_I830(dev)) - I915_WRITE(LVDS, dev_priv->regfile.saveLVDS); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + mask = ~LVDS_PORT_EN; + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask); + else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) + I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask); if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 9462081..d5e1890 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -49,7 +49,7 @@ static ssize_t show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); - return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev)); + return snprintf(buf, PAGE_SIZE, "%x\n", intel_enable_rc6(dminor->dev)); } static ssize_t @@ -57,7 +57,7 @@ show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); - return snprintf(buf, PAGE_SIZE, "%u", rc6_residency); + return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency); } static ssize_t @@ -65,7 +65,7 @@ show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); - return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); + return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency); } static ssize_t @@ -73,7 +73,7 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf) { struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); - return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency); + return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency); } static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); @@ -215,7 +215,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - return snprintf(buf, PAGE_SIZE, "%d", ret); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) @@ -229,7 +229,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - return snprintf(buf, PAGE_SIZE, "%d", ret); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } static ssize_t gt_max_freq_mhz_store(struct device *kdev, @@ -239,7 +239,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); struct drm_device *dev = minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 val, rp_state_cap, hw_max, hw_min; + u32 val, rp_state_cap, hw_max, hw_min, non_oc_max; ssize_t ret; ret = kstrtou32(buf, 0, &val); @@ -251,7 +251,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - hw_max = (rp_state_cap & 0xff); + hw_max = dev_priv->rps.hw_max; + non_oc_max = (rp_state_cap & 0xff); hw_min = ((rp_state_cap & 0xff0000) >> 16); if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { @@ -259,6 +260,10 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, return -EINVAL; } + if (val > non_oc_max) + DRM_DEBUG("User requested overclocking to %d\n", + val * GT_FREQUENCY_MULTIPLIER); + if (dev_priv->rps.cur_delay > val) gen6_set_rps(dev_priv->dev, val); @@ -280,7 +285,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); - return snprintf(buf, PAGE_SIZE, "%d", ret); + return snprintf(buf, PAGE_SIZE, "%d\n", ret); } static ssize_t gt_min_freq_mhz_store(struct device *kdev, @@ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - hw_max = (rp_state_cap & 0xff); + hw_max = dev_priv->rps.hw_max; hw_min = ((rp_state_cap & 0xff0000) >> 16); if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { @@ -355,7 +360,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr } else { BUG(); } - return snprintf(buf, PAGE_SIZE, "%d", val); + return snprintf(buf, PAGE_SIZE, "%d\n", val); } static const struct attribute *gen6_attrs[] = { diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 55ffba1..95070b2 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -351,12 +351,14 @@ parse_general_features(struct drm_i915_private *dev_priv, dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, general->ssc_freq); dev_priv->display_clock_mode = general->display_clock_mode; - DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n", + dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", dev_priv->int_tv_support, dev_priv->int_crt_support, dev_priv->lvds_use_ssc, dev_priv->lvds_ssc_freq, - dev_priv->display_clock_mode); + dev_priv->display_clock_mode, + dev_priv->fdi_rx_polarity_inverted); } } @@ -692,6 +694,9 @@ intel_parse_bios(struct drm_device *dev) struct bdb_header *bdb = NULL; u8 __iomem *bios = NULL; + if (HAS_PCH_NOP(dev)) + return -ENODEV; + init_vbt_defaults(dev_priv); /* XXX Should this validation be moved to intel_opregion.c? */ diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 36e57f9..e088d6f 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -127,7 +127,9 @@ struct bdb_general_features { /* bits 3 */ u8 disable_smooth_vision:1; u8 single_dvi:1; - u8 rsvd9:6; /* finish byte */ + u8 rsvd9:1; + u8 fdi_rx_polarity_inverted:1; + u8 rsvd10:4; /* finish byte */ /* bits 4 */ u8 legacy_monitor_detect; diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 1ce45a0..58b4a53 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -199,10 +199,14 @@ static int intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_crt_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool intel_crt_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { + struct drm_device *dev = encoder->base.dev; + + if (HAS_PCH_SPLIT(dev)) + pipe_config->has_pch_encoder = true; + return true; } @@ -676,7 +680,6 @@ static void intel_crt_reset(struct drm_connector *connector) */ static const struct drm_encoder_helper_funcs crt_encoder_funcs = { - .mode_fixup = intel_crt_mode_fixup, .mode_set = intel_crt_mode_set, }; @@ -768,8 +771,11 @@ void intel_crt_init(struct drm_device *dev) else crt->adpa_reg = ADPA; + crt->base.compute_config = intel_crt_compute_config; crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; + if (I915_HAS_HOTPLUG(dev)) + crt->base.hpd_pin = HPD_CRT; if (HAS_DDI(dev)) crt->base.get_hw_state = intel_ddi_get_hw_state; else @@ -781,18 +787,14 @@ void intel_crt_init(struct drm_device *dev) drm_sysfs_connector_add(connector); - if (I915_HAS_HOTPLUG(dev)) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (!I915_HAS_HOTPLUG(dev)) + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; /* * Configure the automatic hotplug detection stuff */ crt->force_hotplug_required = 0; - dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; - /* * TODO: find a proper way to discover whether we need to set the the * polarity and link reversal bits or not, instead of relying on the diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 8d0bac3..26a0a57 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -898,6 +898,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) 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, @@ -921,14 +924,14 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; int type = intel_encoder->type; uint32_t temp; if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { temp = TRANS_MSA_SYNC_CLK; - switch (intel_crtc->bpp) { + switch (intel_crtc->config.pipe_bpp) { case 18: temp |= TRANS_MSA_6_BPC; break; @@ -942,22 +945,20 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) temp |= TRANS_MSA_12_BPC; break; default: - temp |= TRANS_MSA_8_BPC; - WARN(1, "%d bpp unsupported by DDI function\n", - intel_crtc->bpp); + BUG(); } I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); } } -void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) +void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 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; enum pipe pipe = intel_crtc->pipe; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; uint32_t temp; @@ -966,7 +967,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) temp = TRANS_DDI_FUNC_ENABLE; temp |= TRANS_DDI_SELECT_PORT(port); - switch (intel_crtc->bpp) { + switch (intel_crtc->config.pipe_bpp) { case 18: temp |= TRANS_DDI_BPC_6; break; @@ -980,8 +981,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) temp |= TRANS_DDI_BPC_12; break; default: - WARN(1, "%d bpp unsupported by transcoder DDI function\n", - intel_crtc->bpp); + BUG(); } if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) @@ -1150,14 +1150,14 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); - return true; + return false; } static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { uint32_t temp, ret; - enum port port; + enum port port = I915_MAX_PORTS; enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); int i; @@ -1173,10 +1173,16 @@ static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, port = i; } - ret = I915_READ(PORT_CLK_SEL(port)); - - DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n", - pipe_name(pipe), port_name(port), ret); + if (port == I915_MAX_PORTS) { + WARN(1, "Pipe %c enabled on an unknown port\n", + pipe_name(pipe)); + ret = PORT_CLK_SEL_NONE; + } else { + ret = I915_READ(PORT_CLK_SEL(port)); + DRM_DEBUG_KMS("Pipe %c connected to port %c using clock " + "0x%08x\n", pipe_name(pipe), port_name(port), + ret); + } return ret; } @@ -1217,7 +1223,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); enum port port = intel_ddi_get_encoder_port(intel_encoder); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; if (cpu_transcoder != TRANSCODER_EDP) I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), @@ -1227,7 +1233,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) { struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; if (cpu_transcoder != TRANSCODER_EDP) I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), @@ -1341,15 +1347,15 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ironlake_edp_backlight_off(intel_dp); } - - tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); - I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) @@ -1467,19 +1473,17 @@ static void intel_ddi_destroy(struct drm_encoder *encoder) intel_dp_encoder_destroy(encoder); } -static bool intel_ddi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool intel_ddi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - int type = intel_encoder->type; + int type = encoder->type; - WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n"); + WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); if (type == INTEL_OUTPUT_HDMI) - return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode); + return intel_hdmi_compute_config(encoder, pipe_config); else - return intel_dp_mode_fixup(encoder, mode, adjusted_mode); + return intel_dp_compute_config(encoder, pipe_config); } static const struct drm_encoder_funcs intel_ddi_funcs = { @@ -1487,7 +1491,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = { }; static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { - .mode_fixup = intel_ddi_mode_fixup, .mode_set = intel_ddi_mode_set, }; @@ -1527,6 +1530,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); + intel_encoder->compute_config = intel_ddi_compute_config; intel_encoder->enable = intel_enable_ddi; intel_encoder->pre_enable = intel_ddi_pre_enable; intel_encoder->disable = intel_disable_ddi; @@ -1537,9 +1541,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & DDI_BUF_PORT_REVERSAL; if (hdmi_connector) - intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); - else - intel_dig_port->hdmi.sdvox_reg = 0; + intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); intel_encoder->type = INTEL_OUTPUT_UNKNOWN; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b20d501..efe8299 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -71,8 +71,24 @@ typedef struct intel_limit intel_limit_t; struct intel_limit { intel_range_t dot, vco, n, m, m1, m2, p, p1; intel_p2_t p2; - bool (* find_pll)(const intel_limit_t *, struct drm_crtc *, - int, int, intel_clock_t *, intel_clock_t *); + /** + * find_pll() - Find the best values for the PLL + * @limit: limits for the PLL + * @crtc: current CRTC + * @target: target frequency in kHz + * @refclk: reference clock frequency in kHz + * @match_clock: if provided, @best_clock P divider must + * match the P divider from @match_clock + * used for LVDS downclocking + * @best_clock: best PLL values found + * + * Returns true on success, false on failure. + */ + bool (*find_pll)(const intel_limit_t *limit, + struct drm_crtc *crtc, + int target, int refclk, + intel_clock_t *match_clock, + intel_clock_t *best_clock); }; /* FDI */ @@ -471,7 +487,6 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) { - /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; else @@ -498,10 +513,8 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_is_dual_link_lvds(dev)) - /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else - /* LVDS with dual channel */ limit = &intel_limits_g4x_single_channel_lvds; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) || intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { @@ -879,7 +892,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - return intel_crtc->cpu_transcoder; + return intel_crtc->config.cpu_transcoder; } static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) @@ -1214,8 +1227,8 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP && - !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) { + if (!intel_using_power_well(dev_priv->dev) && + cpu_transcoder != TRANSCODER_EDP) { cur_state = false; } else { reg = PIPECONF(cpu_transcoder); @@ -1254,7 +1267,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, int cur_pipe; /* Planes are fixed to pipes on ILK+ */ - if (HAS_PCH_SPLIT(dev_priv->dev)) { + if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) { reg = DSPCNTR(pipe); val = I915_READ(reg); WARN((val & DISPLAY_PLANE_ENABLE), @@ -1275,6 +1288,25 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, } } +static void assert_sprites_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg, i; + u32 val; + + if (!IS_VALLEYVIEW(dev_priv->dev)) + return; + + /* Need to check both planes against the pipe */ + for (i = 0; i < dev_priv->num_plane; i++) { + reg = SPCNTR(pipe, i); + val = I915_READ(reg); + WARN((val & SP_ENABLE), + "sprite %d assertion failure, should be off on pipe %c but is still active\n", + pipe * 2 + i, pipe_name(pipe)); + } +} + static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) { u32 val; @@ -1327,14 +1359,14 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe, u32 val) { - if ((val & PORT_ENABLE) == 0) + if ((val & SDVO_ENABLE) == 0) return false; if (HAS_PCH_CPT(dev_priv->dev)) { - if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) + if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe)) return false; } else { - if ((val & TRANSCODER_MASK) != TRANSCODER(pipe)) + if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe)) return false; } return true; @@ -1392,7 +1424,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); - WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0 + WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 && (val & SDVO_PIPE_B_SELECT), "IBX PCH hdmi port still using transcoder B\n"); } @@ -1419,9 +1451,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); - assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB); - assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC); - assert_pch_hdmi_disabled(dev_priv, pipe, HDMID); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); + assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); } /** @@ -1859,6 +1891,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, * or we might hang the display. */ assert_planes_disabled(dev_priv, pipe); + assert_sprites_disabled(dev_priv, pipe); /* Don't disable pipe A or pipe A PLLs if needed */ if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) @@ -1937,6 +1970,15 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, intel_wait_for_vblank(dev_priv->dev, pipe); } +static bool need_vtd_wa(struct drm_device *dev) +{ +#ifdef CONFIG_INTEL_IOMMU + if (INTEL_INFO(dev)->gen >= 6 && intel_iommu_gfx_mapped) + return true; +#endif + return false; +} + int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, @@ -1960,13 +2002,23 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, alignment = 0; break; case I915_TILING_Y: - /* FIXME: Is this true? */ - DRM_ERROR("Y tiled not allowed for scan out buffers\n"); + /* Despite that we check this in framebuffer_init userspace can + * screw us over and change the tiling after the fact. Only + * pinned buffers can't change their tiling. */ + DRM_DEBUG_DRIVER("Y tiled not allowed for scan out buffers\n"); return -EINVAL; default: BUG(); } + /* Note that the w/a also requires 64 PTE of padding following the + * bo. We currently fill all unused PTE with the shadow page and so + * we should always have valid PTE following the scanout preventing + * the VT-d warning. + */ + if (need_vtd_wa(dev) && alignment < 256 * 1024) + alignment = 256 * 1024; + dev_priv->mm.interruptible = false; ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined); if (ret) @@ -2083,8 +2135,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, dspcntr |= DISPPLANE_RGBX101010; break; default: - DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); - return -EINVAL; + BUG(); } if (INTEL_INFO(dev)->gen >= 4) { @@ -2177,8 +2228,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc, dspcntr |= DISPPLANE_RGBX101010; break; default: - DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); - return -EINVAL; + BUG(); } if (obj->tiling_mode != I915_TILING_NONE) @@ -2229,6 +2279,44 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, return dev_priv->display.update_plane(crtc, fb, x, y); } +void intel_display_handle_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + + /* + * Flips in the rings have been nuked by the reset, + * so complete all pending flips so that user space + * will get its events and not get stuck. + * + * Also update the base address of all primary + * planes to the the last fb to make sure we're + * showing the correct fb after a reset. + * + * Need to make two loops over the crtcs so that we + * don't try to grab a crtc mutex before the + * pending_flip_queue really got woken up. + */ + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum plane plane = intel_crtc->plane; + + intel_prepare_page_flip(dev, plane); + intel_finish_page_flip_plane(dev, plane); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + mutex_lock(&crtc->mutex); + if (intel_crtc->active) + dev_priv->display.update_plane(crtc, crtc->fb, + crtc->x, crtc->y); + mutex_unlock(&crtc->mutex); + } +} + static int intel_finish_fb(struct drm_framebuffer *old_fb) { @@ -2295,10 +2383,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } - if(intel_crtc->plane > dev_priv->num_pipe) { + if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n", intel_crtc->plane, - dev_priv->num_pipe); + INTEL_INFO(dev)->num_pipes); return -EINVAL; } @@ -2312,9 +2400,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - if (crtc->fb) - intel_finish_fb(crtc->fb); - ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); @@ -2912,32 +2997,6 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -static bool ironlake_crtc_driving_pch(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct intel_encoder *intel_encoder; - - /* - * If there's a non-PCH eDP on this crtc, it must be DP_A, and that - * must be driven by its own crtc; no sharing is possible. - */ - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - switch (intel_encoder->type) { - case INTEL_OUTPUT_EDP: - if (!intel_encoder_is_pch_edp(&intel_encoder->base)) - return false; - continue; - } - } - - return true; -} - -static bool haswell_crtc_driving_pch(struct drm_crtc *crtc) -{ - return intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG); -} - /* Program iCLKIP clock to the desired frequency */ static void lpt_program_iclkip(struct drm_crtc *crtc) { @@ -3144,7 +3203,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; assert_transcoder_disabled(dev_priv, TRANSCODER_A); @@ -3273,7 +3332,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; u32 temp; - bool is_pch_port; WARN_ON(!crtc->enabled); @@ -3289,9 +3347,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); } - is_pch_port = ironlake_crtc_driving_pch(crtc); - if (is_pch_port) { + if (intel_crtc->config.has_pch_encoder) { /* Note: FDI PLL enabling _must_ be done before we enable the * cpu pipes, hence this is separate from all the other fdi/pch * enabling. */ @@ -3328,10 +3385,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) */ intel_crtc_load_lut(crtc); - intel_enable_pipe(dev_priv, pipe, is_pch_port); + intel_enable_pipe(dev_priv, pipe, + intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); - if (is_pch_port) + if (intel_crtc->config.has_pch_encoder) ironlake_pch_enable(crtc); mutex_lock(&dev->struct_mutex); @@ -3365,7 +3423,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - bool is_pch_port; WARN_ON(!crtc->enabled); @@ -3375,9 +3432,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_update_watermarks(dev); - is_pch_port = haswell_crtc_driving_pch(crtc); - - if (is_pch_port) + if (intel_crtc->config.has_pch_encoder) dev_priv->display.fdi_link_train(crtc); for_each_encoder_on_crtc(dev, crtc, encoder) @@ -3406,12 +3461,13 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); intel_ddi_set_pipe_settings(crtc); - intel_ddi_enable_pipe_func(crtc); + intel_ddi_enable_transcoder_func(crtc); - intel_enable_pipe(dev_priv, pipe, is_pch_port); + intel_enable_pipe(dev_priv, pipe, + intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); - if (is_pch_port) + if (intel_crtc->config.has_pch_encoder) lpt_pch_enable(crtc); mutex_lock(&dev->struct_mutex); @@ -3522,14 +3578,11 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; - bool is_pch_port; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; if (!intel_crtc->active) return; - is_pch_port = haswell_crtc_driving_pch(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); @@ -3546,9 +3599,13 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); - /* Disable PF */ - I915_WRITE(PF_CTL(pipe), 0); - I915_WRITE(PF_WIN_SZ(pipe), 0); + /* XXX: Once we have proper panel fitter state tracking implemented with + * hardware state read/check support we should switch to only disable + * the panel fitter when we know it's used. */ + if (intel_using_power_well(dev)) { + I915_WRITE(PF_CTL(pipe), 0); + I915_WRITE(PF_WIN_SZ(pipe), 0); + } intel_ddi_disable_pipe_clock(intel_crtc); @@ -3556,7 +3613,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (encoder->post_disable) encoder->post_disable(encoder); - if (is_pch_port) { + if (intel_crtc->config.has_pch_encoder) { lpt_disable_pch_transcoder(dev_priv); intel_ddi_fdi_disable(crtc); } @@ -3581,7 +3638,7 @@ static void haswell_crtc_off(struct drm_crtc *crtc) /* Stop saying we're using TRANSCODER_EDP because some other CRTC might * start using it. */ - intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe; + intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe; intel_ddi_put_crtc_pll(crtc); } @@ -3667,6 +3724,26 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) encoder->enable(encoder); } +static void i9xx_pfit_disable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + uint32_t pctl = I915_READ(PFIT_CONTROL); + + assert_pipe_disabled(dev_priv, crtc->pipe); + + if (INTEL_INFO(dev)->gen >= 4) + pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT; + else + pipe = PIPE_B; + + if (pipe == crtc->pipe) { + DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl); + I915_WRITE(PFIT_CONTROL, 0); + } +} + static void i9xx_crtc_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3675,8 +3752,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - u32 pctl; - if (!intel_crtc->active) return; @@ -3696,11 +3771,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_disable_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); - /* Disable pannel fitter if it is on this pipe. */ - pctl = I915_READ(PFIT_CONTROL); - if ((pctl & PFIT_ENABLE) && - ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe) - I915_WRITE(PFIT_CONTROL, 0); + i9xx_pfit_disable(intel_crtc); intel_disable_pll(dev_priv, pipe); @@ -3906,22 +3977,23 @@ bool intel_connector_get_hw_state(struct intel_connector *connector) return encoder->get_hw_state(encoder, &pipe); } -static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool intel_crtc_compute_config(struct drm_crtc *crtc, + struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->dev; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ - if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4) + if (pipe_config->requested_mode.clock * 3 + > IRONLAKE_FDI_FREQ * 4) return false; } /* All interlaced capable intel hw wants timings in frames. Note though * that intel_lvds_mode_fixup does some funny tricks with the crtc * timings, so we need to be careful not to clobber these.*/ - if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET)) + if (!pipe_config->timings_set) drm_mode_set_crtcinfo(adjusted_mode, 0); /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes @@ -3931,6 +4003,14 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, adjusted_mode->hsync_start == adjusted_mode->hdisplay) return false; + if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { + pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ + } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) { + /* only a 8bpc pipe, with 6bpc dither through the panel fitter + * for lvds. */ + pipe_config->pipe_bpp = 8*3; + } + return true; } @@ -4004,26 +4084,36 @@ static int i830_get_display_clock_speed(struct drm_device *dev) } static void -intel_reduce_ratio(uint32_t *num, uint32_t *den) +intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) { - while (*num > 0xffffff || *den > 0xffffff) { + while (*num > DATA_LINK_M_N_MASK || + *den > DATA_LINK_M_N_MASK) { *num >>= 1; *den >>= 1; } } +static void compute_m_n(unsigned int m, unsigned int n, + uint32_t *ret_m, uint32_t *ret_n) +{ + *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); + *ret_m = div_u64((uint64_t) m * *ret_n, n); + intel_reduce_m_n_ratio(ret_m, ret_n); +} + void intel_link_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n) { m_n->tu = 64; - m_n->gmch_m = bits_per_pixel * pixel_clock; - m_n->gmch_n = link_clock * nlanes * 8; - intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - m_n->link_m = pixel_clock; - m_n->link_n = link_clock; - intel_reduce_ratio(&m_n->link_m, &m_n->link_n); + + compute_m_n(bits_per_pixel * pixel_clock, + link_clock * nlanes * 8, + &m_n->gmch_m, &m_n->gmch_n); + + compute_m_n(pixel_clock, link_clock, + &m_n->link_m, &m_n->link_n); } static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) @@ -4034,142 +4124,6 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); } -/** - * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send - * @crtc: CRTC structure - * @mode: requested mode - * - * A pipe may be connected to one or more outputs. Based on the depth of the - * attached framebuffer, choose a good color depth to use on the pipe. - * - * If possible, match the pipe depth to the fb depth. In some cases, this - * isn't ideal, because the connected output supports a lesser or restricted - * set of depths. Resolve that here: - * LVDS typically supports only 6bpc, so clamp down in that case - * HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc - * Displays may support a restricted set as well, check EDID and clamp as - * appropriate. - * DP may want to dither down to 6bpc to fit larger modes - * - * RETURNS: - * Dithering requirement (i.e. false if display bpc and pipe bpc match, - * true if they don't match). - */ -static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - unsigned int *pipe_bpp, - struct drm_display_mode *mode) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_connector *connector; - struct intel_encoder *intel_encoder; - unsigned int display_bpc = UINT_MAX, bpc; - - /* Walk the encoders & connectors on this crtc, get min bpc */ - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - - if (intel_encoder->type == INTEL_OUTPUT_LVDS) { - unsigned int lvds_bpc; - - if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == - LVDS_A3_POWER_UP) - lvds_bpc = 8; - else - lvds_bpc = 6; - - if (lvds_bpc < display_bpc) { - DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc); - display_bpc = lvds_bpc; - } - continue; - } - - /* Not one of the known troublemakers, check the EDID */ - list_for_each_entry(connector, &dev->mode_config.connector_list, - head) { - if (connector->encoder != &intel_encoder->base) - continue; - - /* Don't use an invalid EDID bpc value */ - if (connector->display_info.bpc && - connector->display_info.bpc < display_bpc) { - DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); - display_bpc = connector->display_info.bpc; - } - } - - if (intel_encoder->type == INTEL_OUTPUT_EDP) { - /* Use VBT settings if we have an eDP panel */ - unsigned int edp_bpc = dev_priv->edp.bpp / 3; - - if (edp_bpc && edp_bpc < display_bpc) { - DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); - display_bpc = edp_bpc; - } - continue; - } - - /* - * HDMI is either 12 or 8, so if the display lets 10bpc sneak - * through, clamp it down. (Note: >12bpc will be caught below.) - */ - if (intel_encoder->type == INTEL_OUTPUT_HDMI) { - if (display_bpc > 8 && display_bpc < 12) { - DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); - display_bpc = 12; - } else { - DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); - display_bpc = 8; - } - } - } - - if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - DRM_DEBUG_KMS("Dithering DP to 6bpc\n"); - display_bpc = 6; - } - - /* - * We could just drive the pipe at the highest bpc all the time and - * enable dithering as needed, but that costs bandwidth. So choose - * the minimum value that expresses the full color range of the fb but - * also stays within the max display bpc discovered above. - */ - - switch (fb->depth) { - case 8: - bpc = 8; /* since we go through a colormap */ - break; - case 15: - case 16: - bpc = 6; /* min is 18bpp */ - break; - case 24: - bpc = 8; - break; - case 30: - bpc = 10; - break; - case 48: - bpc = 12; - break; - default: - DRM_DEBUG("unsupported depth, assuming 24 bits\n"); - bpc = min((unsigned int)8, display_bpc); - break; - } - - display_bpc = min(display_bpc, bpc); - - DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n", - bpc, display_bpc); - - *pipe_bpp = display_bpc * 3; - - return display_bpc != bpc; -} - static int vlv_get_refclk(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -4214,37 +4168,38 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) return refclk; } -static void i9xx_adjust_sdvo_tv_clock(struct drm_display_mode *adjusted_mode, - intel_clock_t *clock) +static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc) { + unsigned dotclock = crtc->config.adjusted_mode.clock; + struct dpll *clock = &crtc->config.dpll; + /* SDVO TV has fixed PLL values depend on its clock range, this mirrors vbios setting. */ - if (adjusted_mode->clock >= 100000 - && adjusted_mode->clock < 140500) { + if (dotclock >= 100000 && dotclock < 140500) { clock->p1 = 2; clock->p2 = 10; clock->n = 3; clock->m1 = 16; clock->m2 = 8; - } else if (adjusted_mode->clock >= 140500 - && adjusted_mode->clock <= 200000) { + } else if (dotclock >= 140500 && dotclock <= 200000) { clock->p1 = 1; clock->p2 = 10; clock->n = 6; clock->m1 = 12; clock->m2 = 8; } + + crtc->config.clock_set = true; } -static void i9xx_update_pll_dividers(struct drm_crtc *crtc, - intel_clock_t *clock, +static void i9xx_update_pll_dividers(struct intel_crtc *crtc, intel_clock_t *reduced_clock) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; + int pipe = crtc->pipe; u32 fp, fp2 = 0; + struct dpll *clock = &crtc->config.dpll; if (IS_PINEVIEW(dev)) { fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2; @@ -4260,26 +4215,29 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc, I915_WRITE(FP0(pipe), fp); - intel_crtc->lowfreq_avail = false; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + crtc->lowfreq_avail = false; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && reduced_clock && i915_powersave) { I915_WRITE(FP1(pipe), fp2); - intel_crtc->lowfreq_avail = true; + crtc->lowfreq_avail = true; } else { I915_WRITE(FP1(pipe), fp); } } -static void vlv_update_pll(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - intel_clock_t *clock, intel_clock_t *reduced_clock, - int num_connectors) +static void intel_dp_set_m_n(struct intel_crtc *crtc) { - struct drm_device *dev = crtc->dev; + if (crtc->config.has_pch_encoder) + intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); + else + intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); +} + +static void vlv_update_pll(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; + int pipe = crtc->pipe; u32 dpll, mdiv, pdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; bool is_sdvo; @@ -4287,8 +4245,8 @@ static void vlv_update_pll(struct drm_crtc *crtc, mutex_lock(&dev_priv->dpio_lock); - is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); dpll = DPLL_VGA_MODE_DIS; dpll |= DPLL_EXT_BUFFER_ENABLE_VLV; @@ -4298,11 +4256,11 @@ static void vlv_update_pll(struct drm_crtc *crtc, I915_WRITE(DPLL(pipe), dpll); POSTING_READ(DPLL(pipe)); - bestn = clock->n; - bestm1 = clock->m1; - bestm2 = clock->m2; - bestp1 = clock->p1; - bestp2 = clock->p2; + bestn = crtc->config.dpll.n; + bestm1 = crtc->config.dpll.m1; + bestm2 = crtc->config.dpll.m2; + bestp1 = crtc->config.dpll.p1; + bestp2 = crtc->config.dpll.p2; /* * In Valleyview PLL and program lane counter registers are exposed @@ -4334,8 +4292,8 @@ static void vlv_update_pll(struct drm_crtc *crtc, intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620); - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) - intel_dp_set_m_n(crtc, mode, adjusted_mode); + if (crtc->config.has_dp_encoder) + intel_dp_set_m_n(crtc); I915_WRITE(DPLL(pipe), dpll); @@ -4345,26 +4303,25 @@ static void vlv_update_pll(struct drm_crtc *crtc, temp = 0; if (is_sdvo) { - temp = intel_mode_get_pixel_multiplier(adjusted_mode); - if (temp > 1) - temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - else - temp = 0; + temp = 0; + if (crtc->config.pixel_multiplier > 1) { + temp = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; + } } I915_WRITE(DPLL_MD(pipe), temp); POSTING_READ(DPLL_MD(pipe)); /* Now program lane control registers */ - if(intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) - || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) - { + if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) + || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) { temp = 0x1000C4; if(pipe == 1) temp |= (1 << 21); intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp); } - if(intel_pipe_has_type(crtc,INTEL_OUTPUT_EDP)) - { + + if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { temp = 0x1000C4; if(pipe == 1) temp |= (1 << 21); @@ -4374,40 +4331,39 @@ static void vlv_update_pll(struct drm_crtc *crtc, mutex_unlock(&dev_priv->dpio_lock); } -static void i9xx_update_pll(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - intel_clock_t *clock, intel_clock_t *reduced_clock, +static void i9xx_update_pll(struct intel_crtc *crtc, + intel_clock_t *reduced_clock, int num_connectors) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; - int pipe = intel_crtc->pipe; + int pipe = crtc->pipe; u32 dpll; bool is_sdvo; + struct dpll *clock = &crtc->config.dpll; - i9xx_update_pll_dividers(crtc, clock, reduced_clock); + i9xx_update_pll_dividers(crtc, reduced_clock); - is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); dpll = DPLL_VGA_MODE_DIS; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) dpll |= DPLLB_MODE_LVDS; else dpll |= DPLLB_MODE_DAC_SERIAL; + if (is_sdvo) { - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - if (pixel_multiplier > 1) { - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + if ((crtc->config.pixel_multiplier > 1) && + (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) { + dpll |= (crtc->config.pixel_multiplier - 1) + << SDVO_MULTIPLIER_SHIFT_HIRES; } dpll |= DPLL_DVO_HIGH_SPEED; } - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ @@ -4435,13 +4391,13 @@ static void i9xx_update_pll(struct drm_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); - if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) + if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) dpll |= PLL_REF_INPUT_TVCLKINBC; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) + else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) /* XXX: just matching BIOS for now */ /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ dpll |= 3; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else @@ -4452,12 +4408,12 @@ static void i9xx_update_pll(struct drm_crtc *crtc, POSTING_READ(DPLL(pipe)); udelay(150); - for_each_encoder_on_crtc(dev, crtc, encoder) + for_each_encoder_on_crtc(dev, &crtc->base, encoder) if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) - intel_dp_set_m_n(crtc, mode, adjusted_mode); + if (crtc->config.has_dp_encoder) + intel_dp_set_m_n(crtc); I915_WRITE(DPLL(pipe), dpll); @@ -4468,11 +4424,11 @@ static void i9xx_update_pll(struct drm_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) { u32 temp = 0; if (is_sdvo) { - temp = intel_mode_get_pixel_multiplier(adjusted_mode); - if (temp > 1) - temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - else - temp = 0; + temp = 0; + if (crtc->config.pixel_multiplier > 1) { + temp = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; + } } I915_WRITE(DPLL_MD(pipe), temp); } else { @@ -4485,23 +4441,23 @@ static void i9xx_update_pll(struct drm_crtc *crtc, } } -static void i8xx_update_pll(struct drm_crtc *crtc, +static void i8xx_update_pll(struct intel_crtc *crtc, struct drm_display_mode *adjusted_mode, - intel_clock_t *clock, intel_clock_t *reduced_clock, + intel_clock_t *reduced_clock, int num_connectors) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; - int pipe = intel_crtc->pipe; + int pipe = crtc->pipe; u32 dpll; + struct dpll *clock = &crtc->config.dpll; - i9xx_update_pll_dividers(crtc, clock, reduced_clock); + i9xx_update_pll_dividers(crtc, reduced_clock); dpll = DPLL_VGA_MODE_DIS; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS)) { dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; } else { if (clock->p1 == 2) @@ -4512,11 +4468,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc, dpll |= PLL_P2_DIVIDE_BY_4; } - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT)) - /* XXX: just matching BIOS for now */ - /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ - dpll |= 3; - else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else @@ -4527,7 +4479,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc, POSTING_READ(DPLL(pipe)); udelay(150); - for_each_encoder_on_crtc(dev, crtc, encoder) + for_each_encoder_on_crtc(dev, &crtc->base, encoder) if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); @@ -4552,7 +4504,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_crtc->pipe; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; uint32_t vsyncshift; if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { @@ -4603,22 +4555,92 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); } +static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t pipeconf; + + pipeconf = I915_READ(PIPECONF(intel_crtc->pipe)); + + if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) { + /* Enable pixel doubling when the dot clock is > 90% of the (display) + * core speed. + * + * XXX: No double-wide on 915GM pipe B. Is that the only reason for the + * pipe == 0 check? + */ + if (intel_crtc->config.requested_mode.clock > + dev_priv->display.get_display_clock_speed(dev) * 9 / 10) + pipeconf |= PIPECONF_DOUBLE_WIDE; + else + pipeconf &= ~PIPECONF_DOUBLE_WIDE; + } + + /* default to 8bpc */ + pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); + if (intel_crtc->config.has_dp_encoder) { + if (intel_crtc->config.dither) { + pipeconf |= PIPECONF_6BPC | + PIPECONF_DITHER_EN | + PIPECONF_DITHER_TYPE_SP; + } + } + + if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(&intel_crtc->base, + INTEL_OUTPUT_EDP)) { + if (intel_crtc->config.dither) { + pipeconf |= PIPECONF_6BPC | + PIPECONF_ENABLE | + I965_PIPECONF_ACTIVE; + } + } + + if (HAS_PIPE_CXSR(dev)) { + if (intel_crtc->lowfreq_avail) { + DRM_DEBUG_KMS("enabling CxSR downclocking\n"); + pipeconf |= PIPECONF_CXSR_DOWNCLOCK; + } else { + DRM_DEBUG_KMS("disabling CxSR downclocking\n"); + pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; + } + } + + pipeconf &= ~PIPECONF_INTERLACE_MASK; + if (!IS_GEN2(dev) && + intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) + pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; + else + pipeconf |= PIPECONF_PROGRESSIVE; + + if (IS_VALLEYVIEW(dev)) { + if (intel_crtc->config.limited_color_range) + pipeconf |= PIPECONF_COLOR_RANGE_SELECT; + else + pipeconf &= ~PIPECONF_COLOR_RANGE_SELECT; + } + + I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf); + POSTING_READ(PIPECONF(intel_crtc->pipe)); +} + static int i9xx_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dspcntr, pipeconf; + u32 dspcntr; bool ok, has_reduced_clock = false, is_sdvo = false; - bool is_lvds = false, is_tv = false, is_dp = false; + bool is_lvds = false, is_tv = false; struct intel_encoder *encoder; const intel_limit_t *limit; int ret; @@ -4637,9 +4659,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, case INTEL_OUTPUT_TVOUT: is_tv = true; break; - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; } num_connectors++; @@ -4676,86 +4695,42 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, &clock, &reduced_clock); } + /* Compat-code for transition, will disappear. */ + if (!intel_crtc->config.clock_set) { + intel_crtc->config.dpll.n = clock.n; + intel_crtc->config.dpll.m1 = clock.m1; + intel_crtc->config.dpll.m2 = clock.m2; + intel_crtc->config.dpll.p1 = clock.p1; + intel_crtc->config.dpll.p2 = clock.p2; + } if (is_sdvo && is_tv) - i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); + i9xx_adjust_sdvo_tv_clock(intel_crtc); if (IS_GEN2(dev)) - i8xx_update_pll(crtc, adjusted_mode, &clock, + i8xx_update_pll(intel_crtc, adjusted_mode, has_reduced_clock ? &reduced_clock : NULL, num_connectors); else if (IS_VALLEYVIEW(dev)) - vlv_update_pll(crtc, mode, adjusted_mode, &clock, - has_reduced_clock ? &reduced_clock : NULL, - num_connectors); + vlv_update_pll(intel_crtc); else - i9xx_update_pll(crtc, mode, adjusted_mode, &clock, + i9xx_update_pll(intel_crtc, has_reduced_clock ? &reduced_clock : NULL, num_connectors); - /* setup pipeconf */ - pipeconf = I915_READ(PIPECONF(pipe)); - /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; - if (pipe == 0) - dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; - else - dspcntr |= DISPPLANE_SEL_PIPE_B; - - if (pipe == 0 && INTEL_INFO(dev)->gen < 4) { - /* Enable pixel doubling when the dot clock is > 90% of the (display) - * core speed. - * - * XXX: No double-wide on 915GM pipe B. Is that the only reason for the - * pipe == 0 check? - */ - if (mode->clock > - dev_priv->display.get_display_clock_speed(dev) * 9 / 10) - pipeconf |= PIPECONF_DOUBLE_WIDE; + if (!IS_VALLEYVIEW(dev)) { + if (pipe == 0) + dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; else - pipeconf &= ~PIPECONF_DOUBLE_WIDE; - } - - /* default to 8bpc */ - pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); - if (is_dp) { - if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - pipeconf |= PIPECONF_6BPC | - PIPECONF_DITHER_EN | - PIPECONF_DITHER_TYPE_SP; - } - } - - if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { - if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - pipeconf |= PIPECONF_6BPC | - PIPECONF_ENABLE | - I965_PIPECONF_ACTIVE; - } + dspcntr |= DISPPLANE_SEL_PIPE_B; } DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); - if (HAS_PIPE_CXSR(dev)) { - if (intel_crtc->lowfreq_avail) { - DRM_DEBUG_KMS("enabling CxSR downclocking\n"); - pipeconf |= PIPECONF_CXSR_DOWNCLOCK; - } else { - DRM_DEBUG_KMS("disabling CxSR downclocking\n"); - pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; - } - } - - pipeconf &= ~PIPECONF_INTERLACE_MASK; - if (!IS_GEN2(dev) && - adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) - pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; - else - pipeconf |= PIPECONF_PROGRESSIVE; - intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); /* pipesrc and dspsize control the size that is scaled from, @@ -4766,8 +4741,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, (mode->hdisplay - 1)); I915_WRITE(DSPPOS(plane), 0); - I915_WRITE(PIPECONF(pipe), pipeconf); - POSTING_READ(PIPECONF(pipe)); + i9xx_set_pipeconf(intel_crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_wait_for_vblank(dev, pipe); @@ -4782,12 +4757,26 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static bool i9xx_get_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(PIPECONF(crtc->pipe)); + if (!(tmp & PIPECONF_ENABLE)) + return false; + + return true; +} + static void ironlake_init_pch_refclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; - u32 temp; + u32 val, final; bool has_lvds = false; bool has_cpu_edp = false; bool has_pch_edp = false; @@ -4830,70 +4819,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) * PCH B stepping, previous chipset stepping should be * ignoring this setting. */ - temp = I915_READ(PCH_DREF_CONTROL); + val = I915_READ(PCH_DREF_CONTROL); + + /* As we must carefully and slowly disable/enable each source in turn, + * compute the final state we want first and check if we need to + * make any changes at all. + */ + final = val; + final &= ~DREF_NONSPREAD_SOURCE_MASK; + if (has_ck505) + final |= DREF_NONSPREAD_CK505_ENABLE; + else + final |= DREF_NONSPREAD_SOURCE_ENABLE; + + final &= ~DREF_SSC_SOURCE_MASK; + final &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + final &= ~DREF_SSC1_ENABLE; + + if (has_panel) { + final |= DREF_SSC_SOURCE_ENABLE; + + if (intel_panel_use_ssc(dev_priv) && can_ssc) + final |= DREF_SSC1_ENABLE; + + if (has_cpu_edp) { + if (intel_panel_use_ssc(dev_priv) && can_ssc) + final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; + else + final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; + } else + final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + } else { + final |= DREF_SSC_SOURCE_DISABLE; + final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + } + + if (final == val) + return; + /* Always enable nonspread source */ - temp &= ~DREF_NONSPREAD_SOURCE_MASK; + val &= ~DREF_NONSPREAD_SOURCE_MASK; if (has_ck505) - temp |= DREF_NONSPREAD_CK505_ENABLE; + val |= DREF_NONSPREAD_CK505_ENABLE; else - temp |= DREF_NONSPREAD_SOURCE_ENABLE; + val |= DREF_NONSPREAD_SOURCE_ENABLE; if (has_panel) { - temp &= ~DREF_SSC_SOURCE_MASK; - temp |= DREF_SSC_SOURCE_ENABLE; + val &= ~DREF_SSC_SOURCE_MASK; + val |= DREF_SSC_SOURCE_ENABLE; /* SSC must be turned on before enabling the CPU output */ if (intel_panel_use_ssc(dev_priv) && can_ssc) { DRM_DEBUG_KMS("Using SSC on panel\n"); - temp |= DREF_SSC1_ENABLE; + val |= DREF_SSC1_ENABLE; } else - temp &= ~DREF_SSC1_ENABLE; + val &= ~DREF_SSC1_ENABLE; /* Get SSC going before enabling the outputs */ - I915_WRITE(PCH_DREF_CONTROL, temp); + I915_WRITE(PCH_DREF_CONTROL, val); POSTING_READ(PCH_DREF_CONTROL); udelay(200); - temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; /* Enable CPU source on CPU attached eDP */ if (has_cpu_edp) { if (intel_panel_use_ssc(dev_priv) && can_ssc) { DRM_DEBUG_KMS("Using SSC on eDP\n"); - temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; + val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; } else - temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; + val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; } else - temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + val |= DREF_CPU_SOURCE_OUTPUT_DISABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); + I915_WRITE(PCH_DREF_CONTROL, val); POSTING_READ(PCH_DREF_CONTROL); udelay(200); } else { DRM_DEBUG_KMS("Disabling SSC entirely\n"); - temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; /* Turn off CPU output */ - temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + val |= DREF_CPU_SOURCE_OUTPUT_DISABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); + I915_WRITE(PCH_DREF_CONTROL, val); POSTING_READ(PCH_DREF_CONTROL); udelay(200); /* Turn off the SSC source */ - temp &= ~DREF_SSC_SOURCE_MASK; - temp |= DREF_SSC_SOURCE_DISABLE; + val &= ~DREF_SSC_SOURCE_MASK; + val |= DREF_SSC_SOURCE_DISABLE; /* Turn off SSC1 */ - temp &= ~ DREF_SSC1_ENABLE; + val &= ~DREF_SSC1_ENABLE; - I915_WRITE(PCH_DREF_CONTROL, temp); + I915_WRITE(PCH_DREF_CONTROL, val); POSTING_READ(PCH_DREF_CONTROL); udelay(200); } + + BUG_ON(val != final); } /* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */ @@ -4958,13 +4986,6 @@ static void lpt_init_pch_refclk(struct drm_device *dev) tmp |= (0x12 << 24); intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY); - if (!is_sdv) { - tmp = intel_sbi_read(dev_priv, 0x808C, SBI_MPHY); - tmp &= ~(0x3 << 6); - tmp |= (1 << 6) | (1 << 0); - intel_sbi_write(dev_priv, 0x808C, tmp, SBI_MPHY); - } - if (is_sdv) { tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY); tmp |= 0x7FFF; @@ -5118,7 +5139,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, val = I915_READ(PIPECONF(pipe)); val &= ~PIPECONF_BPC_MASK; - switch (intel_crtc->bpp) { + switch (intel_crtc->config.pipe_bpp) { case 18: val |= PIPECONF_6BPC; break; @@ -5146,7 +5167,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, else val |= PIPECONF_PROGRESSIVE; - if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + if (intel_crtc->config.limited_color_range) val |= PIPECONF_COLOR_RANGE_SELECT; else val &= ~PIPECONF_COLOR_RANGE_SELECT; @@ -5162,8 +5183,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, * is supported, but eventually this should handle various * RGB<->YCbCr scenarios as well. */ -static void intel_set_pipe_csc(struct drm_crtc *crtc, - const struct drm_display_mode *adjusted_mode) +static void intel_set_pipe_csc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -5178,7 +5198,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc, * consideration. */ - if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + if (intel_crtc->config.limited_color_range) coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */ /* @@ -5202,7 +5222,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc, if (INTEL_INFO(dev)->gen > 6) { uint16_t postoff = 0; - if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + if (intel_crtc->config.limited_color_range) postoff = (16 * (1 << 13) / 255) & 0x1fff; I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff); @@ -5213,7 +5233,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc, } else { uint32_t mode = CSC_MODE_YUV_TO_RGB; - if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + if (intel_crtc->config.limited_color_range) mode |= CSC_BLACK_SCREEN_OFFSET; I915_WRITE(PIPE_CSC_MODE(pipe), mode); @@ -5226,7 +5246,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc, { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; uint32_t val; val = I915_READ(PIPECONF(cpu_transcoder)); @@ -5303,7 +5323,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, } if (is_sdvo && is_tv) - i9xx_adjust_sdvo_tv_clock(adjusted_mode, clock); + i9xx_adjust_sdvo_tv_clock(to_intel_crtc(crtc)); return true; } @@ -5344,7 +5364,7 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) return false; } - if (dev_priv->num_pipe == 2) + if (INTEL_INFO(dev)->num_pipes == 2) return true; switch (intel_crtc->pipe) { @@ -5401,87 +5421,87 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp) return bps / (link_bw * 8) + 1; } -static void ironlake_set_m_n(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; - struct intel_encoder *intel_encoder, *edp_encoder = NULL; - struct intel_link_m_n m_n = {0}; - int target_clock, pixel_multiplier, lane, link_bw; - bool is_dp = false, is_cpu_edp = false; + int pipe = crtc->pipe; - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - switch (intel_encoder->type) { - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; - case INTEL_OUTPUT_EDP: - is_dp = true; - if (!intel_encoder_is_pch_edp(&intel_encoder->base)) - is_cpu_edp = true; - edp_encoder = intel_encoder; - break; - } - } + I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n); + I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m); + I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n); +} + +void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + enum transcoder transcoder = crtc->config.cpu_transcoder; - /* FDI link */ - pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - lane = 0; - /* CPU eDP doesn't require FDI link, so just set DP M/N - according to current link config */ - if (is_cpu_edp) { - intel_edp_link_config(edp_encoder, &lane, &link_bw); + if (INTEL_INFO(dev)->gen >= 5) { + I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); + I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); } else { - /* FDI is a binary signal running at ~2.7GHz, encoding - * each output octet as 10 bits. The actual frequency - * is stored as a divider into a 100MHz clock, and the - * mode pixel clock is stored in units of 1KHz. - * Hence the bw of each lane in terms of the mode signal - * is: - */ - link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; + I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n); + I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m); + I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n); } +} + +static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct intel_link_m_n m_n = {0}; + int target_clock, lane, link_bw; + + /* FDI is a binary signal running at ~2.7GHz, encoding + * each output octet as 10 bits. The actual frequency + * is stored as a divider into a 100MHz clock, and the + * mode pixel clock is stored in units of 1KHz. + * Hence the bw of each lane in terms of the mode signal + * is: + */ + link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; - /* [e]DP over FDI requires target mode clock instead of link clock. */ - if (edp_encoder) - target_clock = intel_edp_target_clock(edp_encoder, mode); - else if (is_dp) - target_clock = mode->clock; + if (intel_crtc->config.pixel_target_clock) + target_clock = intel_crtc->config.pixel_target_clock; else target_clock = adjusted_mode->clock; - if (!lane) - lane = ironlake_get_lanes_required(target_clock, link_bw, - intel_crtc->bpp); + lane = ironlake_get_lanes_required(target_clock, link_bw, + intel_crtc->config.pipe_bpp); intel_crtc->fdi_lanes = lane; - if (pixel_multiplier > 1) - link_bw *= pixel_multiplier; - intel_link_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n); + if (intel_crtc->config.pixel_multiplier > 1) + link_bw *= intel_crtc->config.pixel_multiplier; + intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock, + link_bw, &m_n); - I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); - I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m); - I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n); + intel_cpu_transcoder_set_m_n(intel_crtc, &m_n); } static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, - struct drm_display_mode *adjusted_mode, - intel_clock_t *clock, u32 fp) + intel_clock_t *clock, u32 *fp, + intel_clock_t *reduced_clock, u32 *fp2) { struct drm_crtc *crtc = &intel_crtc->base; struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; uint32_t dpll; - int factor, pixel_multiplier, num_connectors = 0; + int factor, num_connectors = 0; bool is_lvds = false, is_sdvo = false, is_tv = false; - bool is_dp = false, is_cpu_edp = false; for_each_encoder_on_crtc(dev, crtc, intel_encoder) { switch (intel_encoder->type) { @@ -5497,14 +5517,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, case INTEL_OUTPUT_TVOUT: is_tv = true; break; - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; - case INTEL_OUTPUT_EDP: - is_dp = true; - if (!intel_encoder_is_pch_edp(&intel_encoder->base)) - is_cpu_edp = true; - break; } num_connectors++; @@ -5515,13 +5527,16 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && dev_priv->lvds_ssc_freq == 100) || - intel_is_dual_link_lvds(dev)) + (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (is_sdvo && is_tv) factor = 20; if (clock->m < factor * clock->n) - fp |= FP_CB_TUNE; + *fp |= FP_CB_TUNE; + + if (fp2 && (reduced_clock->m < factor * reduced_clock->n)) + *fp2 |= FP_CB_TUNE; dpll = 0; @@ -5530,13 +5545,14 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; if (is_sdvo) { - pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); - if (pixel_multiplier > 1) { - dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; + if (intel_crtc->config.pixel_multiplier > 1) { + dpll |= (intel_crtc->config.pixel_multiplier - 1) + << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } dpll |= DPLL_DVO_HIGH_SPEED; } - if (is_dp && !is_cpu_edp) + if (intel_crtc->config.has_dp_encoder && + intel_crtc->config.has_pch_encoder) dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ @@ -5574,21 +5590,22 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, } static int ironlake_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dpll, fp = 0, fp2 = 0; bool ok, has_reduced_clock = false; - bool is_lvds = false, is_dp = false, is_cpu_edp = false; + bool is_lvds = false; struct intel_encoder *encoder; int ret; bool dither, fdi_config_ok; @@ -5598,14 +5615,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, case INTEL_OUTPUT_LVDS: is_lvds = true; break; - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; - case INTEL_OUTPUT_EDP: - is_dp = true; - if (!intel_encoder_is_pch_edp(&encoder->base)) - is_cpu_edp = true; - break; } num_connectors++; @@ -5614,19 +5623,28 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); + intel_crtc->config.cpu_transcoder = pipe; + ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, &reduced_clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); return -EINVAL; } + /* Compat-code for transition, will disappear. */ + if (!intel_crtc->config.clock_set) { + intel_crtc->config.dpll.n = clock.n; + intel_crtc->config.dpll.m1 = clock.m1; + intel_crtc->config.dpll.m2 = clock.m2; + intel_crtc->config.dpll.p1 = clock.p1; + intel_crtc->config.dpll.p2 = clock.p2; + } /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); /* determine panel color depth */ - dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, - adjusted_mode); + dither = intel_crtc->config.dither; if (is_lvds && dev_priv->lvds_dither) dither = true; @@ -5635,13 +5653,14 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | reduced_clock.m2; - dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp); + dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock, + has_reduced_clock ? &fp2 : NULL); DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ - if (!is_cpu_edp) { + if (intel_crtc->config.has_pch_encoder) { struct intel_pch_pll *pll; pll = intel_get_pch_pll(intel_crtc, dpll, fp); @@ -5653,8 +5672,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else intel_put_pch_pll(intel_crtc); - if (is_dp && !is_cpu_edp) - intel_dp_set_m_n(crtc, mode, adjusted_mode); + if (intel_crtc->config.has_dp_encoder) + intel_dp_set_m_n(intel_crtc); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_pll_enable) @@ -5689,7 +5708,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Note, this also computes intel_crtc->fdi_lanes which is used below in * ironlake_check_fdi_lanes. */ - ironlake_set_m_n(crtc, mode, adjusted_mode); + intel_crtc->fdi_lanes = 0; + if (intel_crtc->config.has_pch_encoder) + ironlake_fdi_set_m_n(crtc); fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); @@ -5710,6 +5731,23 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, return fdi_config_ok ? ret : -EINVAL; } +static bool ironlake_get_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(PIPECONF(crtc->pipe)); + if (!(tmp & PIPECONF_ENABLE)) + return false; + + if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE) + pipe_config->has_pch_encoder = true; + + return true; +} + static void haswell_modeset_global_resources(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5740,29 +5778,26 @@ static void haswell_modeset_global_resources(struct drm_device *dev) } static int haswell_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; - bool is_dp = false, is_cpu_edp = false; + bool is_cpu_edp = false; struct intel_encoder *encoder; int ret; bool dither; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { - case INTEL_OUTPUT_DISPLAYPORT: - is_dp = true; - break; case INTEL_OUTPUT_EDP: - is_dp = true; if (!intel_encoder_is_pch_edp(&encoder->base)) is_cpu_edp = true; break; @@ -5772,9 +5807,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, } if (is_cpu_edp) - intel_crtc->cpu_transcoder = TRANSCODER_EDP; + intel_crtc->config.cpu_transcoder = TRANSCODER_EDP; else - intel_crtc->cpu_transcoder = pipe; + intel_crtc->config.cpu_transcoder = pipe; /* We are not sure yet this won't happen. */ WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", @@ -5783,7 +5818,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", num_connectors, pipe_name(pipe)); - WARN_ON(I915_READ(PIPECONF(intel_crtc->cpu_transcoder)) & + WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) & (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE)); WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE); @@ -5795,25 +5830,24 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, intel_crtc_update_cursor(crtc, true); /* determine panel color depth */ - dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, - adjusted_mode); + dither = intel_crtc->config.dither; DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); - if (is_dp && !is_cpu_edp) - intel_dp_set_m_n(crtc, mode, adjusted_mode); + if (intel_crtc->config.has_dp_encoder) + intel_dp_set_m_n(intel_crtc); intel_crtc->lowfreq_avail = false; intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); - if (!is_dp || is_cpu_edp) - ironlake_set_m_n(crtc, mode, adjusted_mode); + if (intel_crtc->config.has_pch_encoder) + ironlake_fdi_set_m_n(crtc); haswell_set_pipeconf(crtc, adjusted_mode, dither); - intel_set_pipe_csc(crtc, adjusted_mode); + intel_set_pipe_csc(crtc); /* Set up the display plane register */ I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); @@ -5828,9 +5862,32 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static bool haswell_get_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder)); + if (!(tmp & PIPECONF_ENABLE)) + return false; + + /* + * aswell has only FDI/PCH transcoder A. It is which is connected to + * DDI E. So just check whether this pipe is wired to DDI E and whether + * the PCH transcoder is on. + */ + tmp = I915_READ(TRANS_DDI_FUNC_CTL(crtc->pipe)); + if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && + I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) + pipe_config->has_pch_encoder = true; + + + return true; +} + static int intel_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *fb) { @@ -5839,13 +5896,16 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_encoder_helper_funcs *encoder_funcs; struct intel_encoder *encoder; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int ret; drm_vblank_pre_modeset(dev, pipe); - ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode, - x, y, fb); + ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb); + drm_vblank_post_modeset(dev, pipe); if (ret != 0) @@ -5856,8 +5916,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, encoder->base.base.id, drm_get_encoder_name(&encoder->base), mode->base.id, mode->name); - encoder_funcs = encoder->base.helper_private; - encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode); + if (encoder->mode_set) { + encoder->mode_set(encoder); + } else { + encoder_funcs = encoder->base.helper_private; + encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode); + } } return 0; @@ -6325,13 +6389,24 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { + unsigned alignment; + if (obj->tiling_mode) { DRM_ERROR("cursor cannot be tiled\n"); ret = -EINVAL; goto fail_locked; } - ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL); + /* Note that the w/a also requires 2 PTE of padding following + * the bo. We currently fill all unused PTE with the shadow + * page and so we should always have valid PTE following the + * cursor preventing the VT-d warning. + */ + alignment = 0; + if (need_vtd_wa(dev)) + alignment = 64*1024; + + ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL); if (ret) { DRM_ERROR("failed to move cursor bo into the GTT\n"); goto fail_locked; @@ -6436,20 +6511,6 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, intel_crtc_load_lut(crtc); } -/** - * Get a pipe with a simple mode set on it for doing load-based monitor - * detection. - * - * It will be up to the load-detect code to adjust the pipe as appropriate for - * its requirements. The pipe will be connected to no other encoders. - * - * Currently this code will only succeed if there is a pipe with no encoders - * configured for it. In the future, it could choose to temporarily disable - * some outputs to free up a pipe for its use. - * - * \return crtc, or NULL if no pipes are available. - */ - /* VESA 640x480x72Hz mode to set on the pipe */ static struct drm_display_mode load_detect_mode = { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, @@ -6776,7 +6837,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; struct drm_display_mode *mode; int htot = I915_READ(HTOTAL(cpu_transcoder)); int hsync = I915_READ(HSYNC(cpu_transcoder)); @@ -6954,7 +7015,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; - struct drm_i915_gem_object *obj; unsigned long flags; /* Ignore early vblank irqs */ @@ -6984,8 +7044,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev, spin_unlock_irqrestore(&dev->event_lock, flags); - obj = work->old_fb_obj; - wake_up_all(&dev_priv->pending_flip_queue); queue_work(dev_priv->wq, &work->work); @@ -7473,19 +7531,93 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) } } -static struct drm_display_mode * -intel_modeset_adjusted_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode) +static int +pipe_config_set_bpp(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector *connector; + int bpp; + + switch (fb->pixel_format) { + case DRM_FORMAT_C8: + bpp = 8*3; /* since we go through a colormap */ + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: + /* checked in intel_framebuffer_init already */ + if (WARN_ON(INTEL_INFO(dev)->gen > 3)) + return -EINVAL; + case DRM_FORMAT_RGB565: + bpp = 6*3; /* min is 18bpp */ + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + /* checked in intel_framebuffer_init already */ + if (WARN_ON(INTEL_INFO(dev)->gen < 4)) + return -EINVAL; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + bpp = 8*3; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + /* checked in intel_framebuffer_init already */ + if (WARN_ON(INTEL_INFO(dev)->gen < 4)) + return -EINVAL; + bpp = 10*3; + break; + /* TODO: gen4+ supports 16 bpc floating point, too. */ + default: + DRM_DEBUG_KMS("unsupported depth\n"); + return -EINVAL; + } + + pipe_config->pipe_bpp = bpp; + + /* Clamp display bpp to EDID value */ + list_for_each_entry(connector, &dev->mode_config.connector_list, + head) { + if (connector->encoder && connector->encoder->crtc != crtc) + continue; + + /* Don't use an invalid EDID bpc value */ + if (connector->display_info.bpc && + connector->display_info.bpc * 3 < bpp) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", + bpp, connector->display_info.bpc*3); + pipe_config->pipe_bpp = connector->display_info.bpc*3; + } + } + + return bpp; +} + +static struct intel_crtc_config * +intel_modeset_pipe_config(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; - struct drm_display_mode *adjusted_mode; struct drm_encoder_helper_funcs *encoder_funcs; struct intel_encoder *encoder; + struct intel_crtc_config *pipe_config; + int plane_bpp; - adjusted_mode = drm_mode_duplicate(dev, mode); - if (!adjusted_mode) + pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); + if (!pipe_config) return ERR_PTR(-ENOMEM); + drm_mode_copy(&pipe_config->adjusted_mode, mode); + drm_mode_copy(&pipe_config->requested_mode, mode); + + plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config); + if (plane_bpp < 0) + goto fail; + /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. @@ -7495,23 +7627,38 @@ intel_modeset_adjusted_mode(struct drm_crtc *crtc, if (&encoder->new_crtc->base != crtc) continue; + + if (encoder->compute_config) { + if (!(encoder->compute_config(encoder, pipe_config))) { + DRM_DEBUG_KMS("Encoder config failure\n"); + goto fail; + } + + continue; + } + encoder_funcs = encoder->base.helper_private; - if (!(encoder_funcs->mode_fixup(&encoder->base, mode, - adjusted_mode))) { + if (!(encoder_funcs->mode_fixup(&encoder->base, + &pipe_config->requested_mode, + &pipe_config->adjusted_mode))) { DRM_DEBUG_KMS("Encoder fixup failed\n"); goto fail; } } - if (!(intel_crtc_mode_fixup(crtc, mode, adjusted_mode))) { + if (!(intel_crtc_compute_config(crtc, pipe_config))) { DRM_DEBUG_KMS("CRTC fixup failed\n"); goto fail; } DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - return adjusted_mode; + pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; + DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", + plane_bpp, pipe_config->pipe_bpp, pipe_config->dither); + + return pipe_config; fail: - drm_mode_destroy(dev, adjusted_mode); + kfree(pipe_config); return ERR_PTR(-EINVAL); } @@ -7589,22 +7736,25 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, if (crtc->enabled) *prepare_pipes |= 1 << intel_crtc->pipe; - /* We only support modeset on one single crtc, hence we need to do that - * only for the passed in crtc iff we change anything else than just - * disable crtcs. - * - * This is actually not true, to be fully compatible with the old crtc - * helper we automatically disable _any_ output (i.e. doesn't need to be - * connected to the crtc we're modesetting on) if it's disconnected. - * Which is a rather nutty api (since changed the output configuration - * without userspace's explicit request can lead to confusion), but - * alas. Hence we currently need to modeset on all pipes we prepare. */ + /* + * For simplicity do a full modeset on any pipe where the output routing + * changed. We could be more clever, but that would require us to be + * more careful with calling the relevant encoder->mode_set functions. + */ if (*prepare_pipes) *modeset_pipes = *prepare_pipes; /* ... and mask these out. */ *modeset_pipes &= ~(*disable_pipes); *prepare_pipes &= ~(*disable_pipes); + + /* + * HACK: We don't (yet) fully support global modesets. intel_set_config + * obies this rule, but the modeset restore mode of + * intel_modeset_setup_hw_state does not. + */ + *modeset_pipes &= 1 << intel_crtc->pipe; + *prepare_pipes &= 1 << intel_crtc->pipe; } static bool intel_crtc_in_use(struct drm_crtc *crtc) @@ -7673,12 +7823,29 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) \ +static bool +intel_pipe_config_compare(struct intel_crtc_config *current_config, + struct intel_crtc_config *pipe_config) +{ + if (current_config->has_pch_encoder != pipe_config->has_pch_encoder) { + DRM_ERROR("mismatch in has_pch_encoder " + "(expected %i, found %i)\n", + current_config->has_pch_encoder, + pipe_config->has_pch_encoder); + return false; + } + + return true; +} + void intel_modeset_check_state(struct drm_device *dev) { + drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; + struct intel_crtc_config pipe_config; list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { @@ -7767,17 +7934,27 @@ intel_modeset_check_state(struct drm_device *dev) "crtc's computed enabled state doesn't match tracked enabled state " "(expected %i, found %i)\n", enabled, crtc->base.enabled); - assert_pipe(dev->dev_private, crtc->pipe, crtc->active); + memset(&pipe_config, 0, sizeof(pipe_config)); + active = dev_priv->display.get_pipe_config(crtc, + &pipe_config); + WARN(crtc->active != active, + "crtc active state doesn't match with hw state " + "(expected %i, found %i)\n", crtc->active, active); + + WARN(active && + !intel_pipe_config_compare(&crtc->config, &pipe_config), + "pipe state doesn't match!\n"); } } -int intel_set_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb) +static int __intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode; + struct drm_display_mode *saved_mode, *saved_hwmode; + struct intel_crtc_config *pipe_config = NULL; struct intel_crtc *intel_crtc; unsigned disable_pipes, prepare_pipes, modeset_pipes; int ret = 0; @@ -7790,12 +7967,6 @@ int intel_set_mode(struct drm_crtc *crtc, intel_modeset_affected_pipes(crtc, &modeset_pipes, &prepare_pipes, &disable_pipes); - DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", - modeset_pipes, prepare_pipes, disable_pipes); - - for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) - intel_crtc_disable(&intel_crtc->base); - *saved_hwmode = crtc->hwmode; *saved_mode = crtc->mode; @@ -7804,15 +7975,22 @@ int intel_set_mode(struct drm_crtc *crtc, * Hence simply check whether any bit is set in modeset_pipes in all the * pieces of code that are not yet converted to deal with mutliple crtcs * changing their mode at the same time. */ - adjusted_mode = NULL; if (modeset_pipes) { - adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); - if (IS_ERR(adjusted_mode)) { - ret = PTR_ERR(adjusted_mode); + pipe_config = intel_modeset_pipe_config(crtc, fb, mode); + if (IS_ERR(pipe_config)) { + ret = PTR_ERR(pipe_config); + pipe_config = NULL; + goto out; } } + DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", + modeset_pipes, prepare_pipes, disable_pipes); + + for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) + intel_crtc_disable(&intel_crtc->base); + for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { if (intel_crtc->base.enabled) dev_priv->display.crtc_disable(&intel_crtc->base); @@ -7821,8 +7999,14 @@ int intel_set_mode(struct drm_crtc *crtc, /* crtc->mode is already used by the ->mode_set callbacks, hence we need * to set it here already despite that we pass it down the callchain. */ - if (modeset_pipes) + if (modeset_pipes) { + enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder; crtc->mode = *mode; + /* mode_set/enable/disable functions rely on a correct pipe + * config. */ + to_intel_crtc(crtc)->config = *pipe_config; + to_intel_crtc(crtc)->config.cpu_transcoder = tmp; + } /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ @@ -7836,7 +8020,6 @@ int intel_set_mode(struct drm_crtc *crtc, */ for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { ret = intel_crtc_mode_set(&intel_crtc->base, - mode, adjusted_mode, x, y, fb); if (ret) goto done; @@ -7848,7 +8031,7 @@ int intel_set_mode(struct drm_crtc *crtc, if (modeset_pipes) { /* Store real post-adjustment hardware mode. */ - crtc->hwmode = *adjusted_mode; + crtc->hwmode = pipe_config->adjusted_mode; /* Calculate and store various constants which * are later needed by vblank and swap-completion @@ -7859,19 +8042,31 @@ int intel_set_mode(struct drm_crtc *crtc, /* FIXME: add subpixel order */ done: - drm_mode_destroy(dev, adjusted_mode); if (ret && crtc->enabled) { crtc->hwmode = *saved_hwmode; crtc->mode = *saved_mode; - } else { - intel_modeset_check_state(dev); } out: + kfree(pipe_config); kfree(saved_mode); return ret; } +int intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) +{ + int ret; + + ret = __intel_set_mode(crtc, mode, x, y, fb); + + if (ret == 0) + intel_modeset_check_state(crtc->dev); + + return ret; +} + void intel_crtc_restore_mode(struct drm_crtc *crtc) { intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); @@ -7959,10 +8154,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, config->mode_changed = true; } else if (set->fb == NULL) { config->mode_changed = true; - } else if (set->fb->depth != set->crtc->fb->depth) { - config->mode_changed = true; - } else if (set->fb->bits_per_pixel != - set->crtc->fb->bits_per_pixel) { + } else if (set->fb->pixel_format != + set->crtc->fb->pixel_format) { config->mode_changed = true; } else config->fb_changed = true; @@ -8145,6 +8338,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) goto fail; } } else if (config->fb_changed) { + intel_crtc_wait_for_pending_flips(set->crtc); + ret = intel_pipe_set_base(set->crtc, set->x, set->y, set->fb); } @@ -8221,7 +8416,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) /* Swap pipes & planes for FBC on pre-965 */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - intel_crtc->cpu_transcoder = pipe; + intel_crtc->config.cpu_transcoder = pipe; if (IS_MOBILE(dev) && IS_GEN3(dev)) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; @@ -8232,8 +8427,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; - intel_crtc->bpp = 24; /* default for pre-Ironlake */ - drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); } @@ -8314,7 +8507,7 @@ static void intel_setup_outputs(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, 0); } - if (!(HAS_DDI(dev) && (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) + if (!IS_ULT(dev)) intel_crt_init(dev); if (HAS_DDI(dev)) { @@ -8343,20 +8536,20 @@ static void intel_setup_outputs(struct drm_device *dev) if (has_edp_a(dev)) intel_dp_init(dev, DP_A, PORT_A); - if (I915_READ(HDMIB) & PORT_DETECTED) { + if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, PCH_SDVOB, true); if (!found) - intel_hdmi_init(dev, HDMIB, PORT_B); + intel_hdmi_init(dev, PCH_HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) intel_dp_init(dev, PCH_DP_B, PORT_B); } - if (I915_READ(HDMIC) & PORT_DETECTED) - intel_hdmi_init(dev, HDMIC, PORT_C); + if (I915_READ(PCH_HDMIC) & SDVO_DETECTED) + intel_hdmi_init(dev, PCH_HDMIC, PORT_C); - if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED) - intel_hdmi_init(dev, HDMID, PORT_D); + if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED) + intel_hdmi_init(dev, PCH_HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) intel_dp_init(dev, PCH_DP_C, PORT_C); @@ -8368,24 +8561,21 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); - if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) { - intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, + PORT_B); if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); } - - if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C); - } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; - if (I915_READ(SDVOB) & SDVO_DETECTED) { + if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOB\n"); - found = intel_sdvo_init(dev, SDVOB, true); + found = intel_sdvo_init(dev, GEN3_SDVOB, true); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); - intel_hdmi_init(dev, SDVOB, PORT_B); + intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); } if (!found && SUPPORTS_INTEGRATED_DP(dev)) { @@ -8396,16 +8586,16 @@ static void intel_setup_outputs(struct drm_device *dev) /* Before G4X SDVOC doesn't have its own detect register */ - if (I915_READ(SDVOB) & SDVO_DETECTED) { + if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOC\n"); - found = intel_sdvo_init(dev, SDVOC, false); + found = intel_sdvo_init(dev, GEN3_SDVOC, false); } - if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { + if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { if (SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); - intel_hdmi_init(dev, SDVOC, PORT_C); + intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); } if (SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_C\n"); @@ -8572,20 +8762,22 @@ static void intel_init_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* We always want a DPMS function */ if (HAS_DDI(dev)) { + dev_priv->display.get_pipe_config = haswell_get_pipe_config; dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; dev_priv->display.off = haswell_crtc_off; dev_priv->display.update_plane = ironlake_update_plane; } else if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.get_pipe_config = ironlake_get_pipe_config; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; dev_priv->display.off = ironlake_crtc_off; dev_priv->display.update_plane = ironlake_update_plane; } else { + dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; @@ -8828,7 +9020,7 @@ void intel_modeset_init_hw(struct drm_device *dev) void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i, ret; + int i, j, ret; drm_mode_config_init(dev); @@ -8844,6 +9036,9 @@ void intel_modeset_init(struct drm_device *dev) intel_init_pm(dev); + if (INTEL_INFO(dev)->num_pipes == 0) + return; + intel_init_display(dev); if (IS_GEN2(dev)) { @@ -8859,13 +9054,17 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.fb_base = dev_priv->gtt.mappable_base; DRM_DEBUG_KMS("%d display pipe%s available.\n", - dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : ""); + INTEL_INFO(dev)->num_pipes, + INTEL_INFO(dev)->num_pipes > 1 ? "s" : ""); - for (i = 0; i < dev_priv->num_pipe; i++) { + for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { intel_crtc_init(dev, i); - ret = intel_plane_init(dev, i); - if (ret) - DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret); + for (j = 0; j < dev_priv->num_plane; j++) { + ret = intel_plane_init(dev, i, j); + if (ret) + DRM_DEBUG_KMS("pipe %d plane %d init failed: %d\n", + i, j, ret); + } } intel_cpu_pll_init(dev); @@ -8918,10 +9117,11 @@ static void intel_enable_pipe_a(struct drm_device *dev) static bool intel_check_plane_mapping(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; u32 reg, val; - if (dev_priv->num_pipe == 1) + if (INTEL_INFO(dev)->num_pipes == 1) return true; reg = DSPCNTR(!crtc->plane); @@ -8941,7 +9141,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) u32 reg; /* Clear any frame start delays used for debugging left by the BIOS */ - reg = PIPECONF(crtc->cpu_transcoder); + reg = PIPECONF(crtc->config.cpu_transcoder); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); /* We need to sanitize the plane -> pipe mapping first because this will @@ -9077,6 +9277,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; u32 tmp; + struct drm_plane *plane; struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; @@ -9096,24 +9297,32 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, case TRANS_DDI_EDP_INPUT_C_ONOFF: pipe = PIPE_C; break; + default: + /* A bogus value has been programmed, disable + * the transcoder */ + WARN(1, "Bogus eDP source %08x\n", tmp); + intel_ddi_disable_transcoder_func(dev_priv, + TRANSCODER_EDP); + goto setup_pipes; } crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - crtc->cpu_transcoder = TRANSCODER_EDP; + crtc->config.cpu_transcoder = TRANSCODER_EDP; DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n", pipe_name(pipe)); } } - for_each_pipe(pipe) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); +setup_pipes: + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + enum transcoder tmp = crtc->config.cpu_transcoder; + memset(&crtc->config, 0, sizeof(crtc->config)); + crtc->config.cpu_transcoder = tmp; - tmp = I915_READ(PIPECONF(crtc->cpu_transcoder)); - if (tmp & PIPECONF_ENABLE) - crtc->active = true; - else - crtc->active = false; + crtc->active = dev_priv->display.get_pipe_config(crtc, + &crtc->config); crtc->base.enabled = crtc->active; @@ -9172,9 +9381,19 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, } if (force_restore) { + /* + * We need to use raw interfaces for restoring state to avoid + * checking (bogus) intermediate states. + */ for_each_pipe(pipe) { - intel_crtc_restore_mode(dev_priv->pipe_to_crtc_mapping[pipe]); + struct drm_crtc *crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + + __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, + crtc->fb); } + list_for_each_entry(plane, &dev->mode_config.plane_list, head) + intel_plane_restore(plane); i915_redisable_vga(dev); } else { @@ -9236,6 +9455,9 @@ 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); + drm_mode_config_cleanup(dev); intel_cleanup_overlay(dev); @@ -9323,15 +9545,24 @@ intel_display_capture_error_state(struct drm_device *dev) for_each_pipe(i) { cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i); - error->cursor[i].control = I915_READ(CURCNTR(i)); - error->cursor[i].position = I915_READ(CURPOS(i)); - error->cursor[i].base = I915_READ(CURBASE(i)); + if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { + error->cursor[i].control = I915_READ(CURCNTR(i)); + error->cursor[i].position = I915_READ(CURPOS(i)); + error->cursor[i].base = I915_READ(CURBASE(i)); + } else { + error->cursor[i].control = I915_READ(CURCNTR_IVB(i)); + error->cursor[i].position = I915_READ(CURPOS_IVB(i)); + error->cursor[i].base = I915_READ(CURBASE_IVB(i)); + } error->plane[i].control = I915_READ(DSPCNTR(i)); error->plane[i].stride = I915_READ(DSPSTRIDE(i)); - error->plane[i].size = I915_READ(DSPSIZE(i)); - error->plane[i].pos = I915_READ(DSPPOS(i)); - error->plane[i].addr = I915_READ(DSPADDR(i)); + if (INTEL_INFO(dev)->gen <= 3) { + error->plane[i].size = I915_READ(DSPSIZE(i)); + error->plane[i].pos = I915_READ(DSPPOS(i)); + } + if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) + error->plane[i].addr = I915_READ(DSPADDR(i)); if (INTEL_INFO(dev)->gen >= 4) { error->plane[i].surface = I915_READ(DSPSURF(i)); error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i)); @@ -9355,10 +9586,9 @@ intel_display_print_error_state(struct seq_file *m, struct drm_device *dev, struct intel_display_error_state *error) { - drm_i915_private_t *dev_priv = dev->dev_private; int i; - seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe); + seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); for_each_pipe(i) { seq_printf(m, "Pipe [%d]:\n", i); seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); @@ -9373,9 +9603,12 @@ intel_display_print_error_state(struct seq_file *m, seq_printf(m, "Plane [%d]:\n", i); seq_printf(m, " CNTR: %08x\n", error->plane[i].control); seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); - seq_printf(m, " SIZE: %08x\n", error->plane[i].size); - seq_printf(m, " POS: %08x\n", error->plane[i].pos); - seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); + if (INTEL_INFO(dev)->gen <= 3) { + seq_printf(m, " SIZE: %08x\n", error->plane[i].size); + seq_printf(m, " POS: %08x\n", error->plane[i].pos); + } + if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) + seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); if (INTEL_INFO(dev)->gen >= 4) { seq_printf(m, " SURF: %08x\n", error->plane[i].surface); seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c3f5bd8..fb2fbc1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -109,29 +109,6 @@ bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) static void intel_dp_link_down(struct intel_dp *intel_dp); -void -intel_edp_link_config(struct intel_encoder *intel_encoder, - int *lane_num, int *link_bw) -{ - struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); - - *lane_num = intel_dp->lane_count; - *link_bw = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); -} - -int -intel_edp_target_clock(struct intel_encoder *intel_encoder, - struct drm_display_mode *mode) -{ - struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); - struct intel_connector *intel_connector = intel_dp->attached_connector; - - if (intel_connector->panel.fixed_mode) - return intel_connector->panel.fixed_mode->clock; - else - return mode->clock; -} - static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { @@ -177,34 +154,6 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes) return (max_link_clock * max_lanes * 8) / 10; } -static bool -intel_dp_adjust_dithering(struct intel_dp *intel_dp, - struct drm_display_mode *mode, - bool adjust_mode) -{ - int max_link_clock = - drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); - int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); - int max_rate, mode_rate; - - mode_rate = intel_dp_link_required(mode->clock, 24); - max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); - - if (mode_rate > max_rate) { - mode_rate = intel_dp_link_required(mode->clock, 18); - if (mode_rate > max_rate) - return false; - - if (adjust_mode) - mode->private_flags - |= INTEL_MODE_DP_FORCE_6BPC; - - return true; - } - - return true; -} - static int intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -212,6 +161,8 @@ intel_dp_mode_valid(struct drm_connector *connector, struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; + int target_clock = mode->clock; + int max_rate, mode_rate, max_lanes, max_link_clock; if (is_edp(intel_dp) && fixed_mode) { if (mode->hdisplay > fixed_mode->hdisplay) @@ -219,9 +170,17 @@ intel_dp_mode_valid(struct drm_connector *connector, if (mode->vdisplay > fixed_mode->vdisplay) return MODE_PANEL; + + target_clock = fixed_mode->clock; } - if (!intel_dp_adjust_dithering(intel_dp, mode, false)) + max_link_clock = drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); + max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); + + max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); + mode_rate = intel_dp_link_required(target_clock, 18); + + if (mode_rate > max_rate) return MODE_CLOCK_HIGH; if (mode->clock < 10000) @@ -294,16 +253,20 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_stat_reg; - return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0; + pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; + return (I915_READ(pp_stat_reg) & PP_ON) != 0; } static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_ctrl_reg; - return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0; + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + return (I915_READ(pp_ctrl_reg) & EDP_FORCE_VDD) != 0; } static void @@ -311,14 +274,19 @@ intel_dp_check_edp(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_stat_reg, pp_ctrl_reg; if (!is_edp(intel_dp)) return; + + pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { WARN(1, "eDP powered off while attempting aux channel communication.\n"); DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", - I915_READ(PCH_PP_STATUS), - I915_READ(PCH_PP_CONTROL)); + I915_READ(pp_stat_reg), + I915_READ(pp_ctrl_reg)); } } @@ -328,29 +296,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ch_ctl = intel_dp->output_reg + 0x10; + uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; uint32_t status; bool done; - if (IS_HASWELL(dev)) { - switch (intel_dig_port->port) { - case PORT_A: - ch_ctl = DPA_AUX_CH_CTL; - break; - case PORT_B: - ch_ctl = PCH_DPB_AUX_CH_CTL; - break; - case PORT_C: - ch_ctl = PCH_DPC_AUX_CH_CTL; - break; - case PORT_D: - ch_ctl = PCH_DPD_AUX_CH_CTL; - break; - default: - BUG(); - } - } - #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) if (has_aux_irq) done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, @@ -370,11 +319,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, uint8_t *recv, int recv_size) { - uint32_t output_reg = intel_dp->output_reg; struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ch_ctl = output_reg + 0x10; + uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; uint32_t ch_data = ch_ctl + 4; int i, ret, recv_bytes; uint32_t status; @@ -388,29 +336,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, */ pm_qos_update_request(&dev_priv->pm_qos, 0); - if (IS_HASWELL(dev)) { - switch (intel_dig_port->port) { - case PORT_A: - ch_ctl = DPA_AUX_CH_CTL; - ch_data = DPA_AUX_CH_DATA1; - break; - case PORT_B: - ch_ctl = PCH_DPB_AUX_CH_CTL; - ch_data = PCH_DPB_AUX_CH_DATA1; - break; - case PORT_C: - ch_ctl = PCH_DPC_AUX_CH_CTL; - ch_data = PCH_DPC_AUX_CH_DATA1; - break; - case PORT_D: - ch_ctl = PCH_DPD_AUX_CH_CTL; - ch_data = PCH_DPD_AUX_CH_DATA1; - break; - default: - BUG(); - } - } - intel_dp_check_edp(intel_dp); /* The clock divider is based off the hrawclk, * and would like to run at 2MHz. So, take the @@ -428,10 +353,14 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ else aux_clock_divider = 225; /* eDP input clock at 450Mhz */ - } else if (HAS_PCH_SPLIT(dev)) + } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { + /* Workaround for non-ULT HSW */ + aux_clock_divider = 74; + } else if (HAS_PCH_SPLIT(dev)) { aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2); - else + } else { aux_clock_divider = intel_hrawclk(dev) / 2; + } if (IS_GEN6(dev)) precharge = 3; @@ -732,18 +661,26 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, } bool -intel_dp_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +intel_dp_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { - struct drm_device *dev = encoder->dev; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + struct drm_display_mode *mode = &pipe_config->requested_mode; + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_connector *intel_connector = intel_dp->attached_connector; int lane_count, clock; int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; int bpp, mode_rate; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; + int target_clock, link_avail, link_clock; + + if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp)) + pipe_config->has_pch_encoder = true; + + pipe_config->has_dp_encoder = true; if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { intel_fixed_panel_mode(intel_connector->panel.fixed_mode, @@ -752,6 +689,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, intel_connector->panel.fitting_mode, mode, adjusted_mode); } + /* We need to take the panel's fixed mode into account. */ + target_clock = adjusted_mode->clock; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) return false; @@ -760,11 +699,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, "max bw %02x pixel clock %iKHz\n", max_lane_count, bws[max_clock], adjusted_mode->clock); - if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, true)) - return false; + /* Walk through all bpp values. Luckily they're all nicely spaced with 2 + * bpc in between. */ + bpp = min_t(int, 8*3, pipe_config->pipe_bpp); + for (; bpp >= 6*3; bpp -= 2*3) { + mode_rate = intel_dp_link_required(target_clock, bpp); + + for (clock = 0; clock <= max_clock; clock++) { + for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { + link_clock = drm_dp_bw_code_to_link_rate(bws[clock]); + link_avail = intel_dp_max_data_rate(link_clock, + lane_count); + + if (mode_rate <= link_avail) { + goto found; + } + } + } + } - bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + return false; +found: if (intel_dp->color_range_auto) { /* * See: @@ -778,104 +734,38 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, } if (intel_dp->color_range) - adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; - - mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); - - for (clock = 0; clock <= max_clock; clock++) { - for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { - int link_bw_clock = - drm_dp_bw_code_to_link_rate(bws[clock]); - int link_avail = intel_dp_max_data_rate(link_bw_clock, - lane_count); - - if (mode_rate <= link_avail) { - intel_dp->link_bw = bws[clock]; - intel_dp->lane_count = lane_count; - adjusted_mode->clock = link_bw_clock; - DRM_DEBUG_KMS("DP link bw %02x lane " - "count %d clock %d bpp %d\n", - intel_dp->link_bw, intel_dp->lane_count, - adjusted_mode->clock, bpp); - DRM_DEBUG_KMS("DP link bw required %i available %i\n", - mode_rate, link_avail); - return true; - } - } - } - - return false; -} + pipe_config->limited_color_range = true; -void -intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct drm_device *dev = crtc->dev; - struct intel_encoder *intel_encoder; - struct intel_dp *intel_dp; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int lane_count = 4; - struct intel_link_m_n m_n; - int pipe = intel_crtc->pipe; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; - int target_clock; + intel_dp->link_bw = bws[clock]; + intel_dp->lane_count = lane_count; + adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); + pipe_config->pixel_target_clock = target_clock; - /* - * Find the lane count in the intel_encoder private - */ - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - intel_dp = enc_to_intel_dp(&intel_encoder->base); + DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n", + intel_dp->link_bw, intel_dp->lane_count, + adjusted_mode->clock, bpp); + DRM_DEBUG_KMS("DP link bw required %i available %i\n", + mode_rate, link_avail); - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || - intel_encoder->type == INTEL_OUTPUT_EDP) - { - lane_count = intel_dp->lane_count; - break; - } - } - - target_clock = mode->clock; - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - if (intel_encoder->type == INTEL_OUTPUT_EDP) { - target_clock = intel_edp_target_clock(intel_encoder, - mode); - break; - } - } + intel_link_compute_m_n(bpp, lane_count, + target_clock, adjusted_mode->clock, + &pipe_config->dp_m_n); /* - * Compute the GMCH and Link ratios. The '3' here is - * the number of bytes_per_pixel post-LUT, which we always - * set up for 8-bits of R/G/B, or 3 bytes total. + * XXX: We have a strange regression where using the vbt edp bpp value + * for the link bw computation results in black screens, the panel only + * works when we do the computation at the usual 24bpp (but still + * requires us to use 18bpp). Until that's fully debugged, stay + * bug-for-bug compatible with the old code. */ - intel_link_compute_m_n(intel_crtc->bpp, lane_count, - target_clock, adjusted_mode->clock, &m_n); - - if (IS_HASWELL(dev)) { - I915_WRITE(PIPE_DATA_M1(cpu_transcoder), - TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); - I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m); - I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n); - } else if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n); - I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m); - I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n); - } else if (IS_VALLEYVIEW(dev)) { - I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); - I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); - I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); - } else { - I915_WRITE(PIPE_GMCH_DATA_M(pipe), - TU_SIZE(m_n.tu) | m_n.gmch_m); - I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n); - I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m); - I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n); + if (is_edp(intel_dp) && dev_priv->edp.bpp) { + DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", + bpp, dev_priv->edp.bpp); + bpp = min_t(int, bpp, dev_priv->edp.bpp); } + pipe_config->pipe_bpp = bpp; + + return true; } void intel_dp_init_link_config(struct intel_dp *intel_dp) @@ -994,7 +884,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, else intel_dp->DP |= DP_PLL_FREQ_270MHZ; } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { - if (!HAS_PCH_SPLIT(dev)) + if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) intel_dp->DP |= intel_dp->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) @@ -1009,7 +899,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_crtc->pipe == 1) intel_dp->DP |= DP_PIPEB_SELECT; - if (is_cpu_edp(intel_dp)) { + if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { /* don't miss out required setting for eDP */ if (adjusted_mode->clock < 200000) intel_dp->DP |= DP_PLL_FREQ_160MHZ; @@ -1020,7 +910,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } - if (is_cpu_edp(intel_dp)) + if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) ironlake_set_pll_edp(crtc, adjusted_mode->clock); } @@ -1039,16 +929,20 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_stat_reg, pp_ctrl_reg; + + pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n", - mask, value, - I915_READ(PCH_PP_STATUS), - I915_READ(PCH_PP_CONTROL)); + mask, value, + I915_READ(pp_stat_reg), + I915_READ(pp_ctrl_reg)); - if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) { + if (_wait_for((I915_READ(pp_stat_reg) & mask) == value, 5000, 10)) { DRM_ERROR("Panel status timeout: status %08x control %08x\n", - I915_READ(PCH_PP_STATUS), - I915_READ(PCH_PP_CONTROL)); + I915_READ(pp_stat_reg), + I915_READ(pp_ctrl_reg)); } } @@ -1075,9 +969,15 @@ static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp) * is locked */ -static u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv) +static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) { - u32 control = I915_READ(PCH_PP_CONTROL); + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + u32 control; + u32 pp_ctrl_reg; + + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + control = I915_READ(pp_ctrl_reg); control &= ~PANEL_UNLOCK_MASK; control |= PANEL_UNLOCK_REGS; @@ -1089,6 +989,7 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + u32 pp_stat_reg, pp_ctrl_reg; if (!is_edp(intel_dp)) return; @@ -1107,13 +1008,16 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) if (!ironlake_edp_have_panel_power(intel_dp)) ironlake_wait_panel_power_cycle(intel_dp); - pp = ironlake_get_pp_control(dev_priv); + pp = ironlake_get_pp_control(intel_dp); pp |= EDP_FORCE_VDD; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", - I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); + pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + + I915_WRITE(pp_ctrl_reg, pp); + POSTING_READ(pp_ctrl_reg); + DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", + I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); /* * If the panel wasn't on, delay before accessing aux channel */ @@ -1128,19 +1032,23 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + u32 pp_stat_reg, pp_ctrl_reg; WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { - pp = ironlake_get_pp_control(dev_priv); + pp = ironlake_get_pp_control(intel_dp); pp &= ~EDP_FORCE_VDD; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - /* Make sure sequencer is idle before allowing subsequent activity */ - DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", - I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); + pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + + I915_WRITE(pp_ctrl_reg, pp); + POSTING_READ(pp_ctrl_reg); + /* 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); } } @@ -1184,6 +1092,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + u32 pp_ctrl_reg; if (!is_edp(intel_dp)) return; @@ -1197,7 +1106,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) ironlake_wait_panel_power_cycle(intel_dp); - pp = ironlake_get_pp_control(dev_priv); + pp = ironlake_get_pp_control(intel_dp); if (IS_GEN5(dev)) { /* ILK workaround: disable reset around power sequence */ pp &= ~PANEL_POWER_RESET; @@ -1209,8 +1118,10 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) if (!IS_GEN5(dev)) pp |= PANEL_POWER_RESET; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + + I915_WRITE(pp_ctrl_reg, pp); + POSTING_READ(pp_ctrl_reg); ironlake_wait_panel_on(intel_dp); @@ -1226,6 +1137,7 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + u32 pp_ctrl_reg; if (!is_edp(intel_dp)) return; @@ -1234,12 +1146,15 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); - pp = ironlake_get_pp_control(dev_priv); + 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); - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + + I915_WRITE(pp_ctrl_reg, pp); + POSTING_READ(pp_ctrl_reg); intel_dp->want_panel_vdd = false; @@ -1253,6 +1168,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe; u32 pp; + u32 pp_ctrl_reg; if (!is_edp(intel_dp)) return; @@ -1265,10 +1181,13 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) * allowing it to appear. */ msleep(intel_dp->backlight_on_delay); - pp = ironlake_get_pp_control(dev_priv); + pp = ironlake_get_pp_control(intel_dp); pp |= EDP_BLC_ENABLE; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + + I915_WRITE(pp_ctrl_reg, pp); + POSTING_READ(pp_ctrl_reg); intel_panel_enable_backlight(dev, pipe); } @@ -1278,6 +1197,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + u32 pp_ctrl_reg; if (!is_edp(intel_dp)) return; @@ -1285,10 +1205,13 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp) intel_panel_disable_backlight(dev); DRM_DEBUG_KMS("\n"); - pp = ironlake_get_pp_control(dev_priv); + pp = ironlake_get_pp_control(intel_dp); pp &= ~EDP_BLC_ENABLE; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + + I915_WRITE(pp_ctrl_reg, pp); + POSTING_READ(pp_ctrl_reg); msleep(intel_dp->backlight_off_delay); } @@ -1384,7 +1307,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, if (!(tmp & DP_PORT_EN)) return false; - if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { + if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { *pipe = PORT_TO_PIPE_CPT(tmp); } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { *pipe = PORT_TO_PIPE(tmp); @@ -1441,10 +1364,12 @@ static void intel_disable_dp(struct intel_encoder *encoder) static void intel_post_disable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct drm_device *dev = encoder->base.dev; if (is_cpu_edp(intel_dp)) { intel_dp_link_down(intel_dp); - ironlake_edp_pll_off(intel_dp); + if (!IS_VALLEYVIEW(dev)) + ironlake_edp_pll_off(intel_dp); } } @@ -1470,8 +1395,9 @@ static void intel_enable_dp(struct intel_encoder *encoder) static void intel_pre_enable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct drm_device *dev = encoder->base.dev; - if (is_cpu_edp(intel_dp)) + if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) ironlake_edp_pll_on(intel_dp); } @@ -1548,7 +1474,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: return DP_TRAIN_PRE_EMPHASIS_9_5; @@ -1756,7 +1682,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) uint32_t signal_levels, mask; uint8_t train_set = intel_dp->train_set[0]; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { signal_levels = intel_hsw_signal_levels(train_set); mask = DDI_BUF_EMP_MASK; } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { @@ -1787,7 +1713,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, int ret; uint32_t temp; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { temp = I915_READ(DP_TP_CTL(port)); if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) @@ -2311,6 +2237,16 @@ g4x_dp_detect(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); uint32_t bit; + /* Can't disconnect eDP, but you can close the lid... */ + if (is_edp(intel_dp)) { + enum drm_connector_status status; + + status = intel_panel_detect(dev); + if (status == connector_status_unknown) + status = connector_status_connected; + return status; + } + switch (intel_dig_port->port) { case PORT_B: bit = PORTB_HOTPLUG_LIVE_STATUS; @@ -2492,6 +2428,9 @@ intel_dp_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_dp->color_range_auto; + uint32_t old_range = intel_dp->color_range; + switch (val) { case INTEL_BROADCAST_RGB_AUTO: intel_dp->color_range_auto = true; @@ -2507,6 +2446,11 @@ intel_dp_set_property(struct drm_connector *connector, default: return -EINVAL; } + + if (old_auto == intel_dp->color_range_auto && + old_range == intel_dp->color_range) + return 0; + goto done; } @@ -2538,17 +2482,14 @@ done: static void intel_dp_destroy(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_connector *intel_connector = to_intel_connector(connector); if (!IS_ERR_OR_NULL(intel_connector->edid)) kfree(intel_connector->edid); - if (is_edp(intel_dp)) { - intel_panel_destroy_backlight(dev); + if (is_edp(intel_dp)) intel_panel_fini(&intel_connector->panel); - } drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -2573,7 +2514,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) } static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { - .mode_fixup = intel_dp_mode_fixup, .mode_set = intel_dp_mode_set, }; @@ -2669,15 +2609,28 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct edp_power_seq cur, vbt, spec, final; u32 pp_on, pp_off, pp_div, pp; + int pp_control_reg, pp_on_reg, pp_off_reg, pp_div_reg; + + if (HAS_PCH_SPLIT(dev)) { + pp_control_reg = PCH_PP_CONTROL; + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_div_reg = PCH_PP_DIVISOR; + } else { + pp_control_reg = PIPEA_PP_CONTROL; + pp_on_reg = PIPEA_PP_ON_DELAYS; + pp_off_reg = PIPEA_PP_OFF_DELAYS; + pp_div_reg = PIPEA_PP_DIVISOR; + } /* Workaround: Need to write PP_CONTROL with the unlock key as * the very first thing. */ - pp = ironlake_get_pp_control(dev_priv); - I915_WRITE(PCH_PP_CONTROL, pp); + pp = ironlake_get_pp_control(intel_dp); + I915_WRITE(pp_control_reg, pp); - pp_on = I915_READ(PCH_PP_ON_DELAYS); - pp_off = I915_READ(PCH_PP_OFF_DELAYS); - pp_div = I915_READ(PCH_PP_DIVISOR); + pp_on = I915_READ(pp_on_reg); + pp_off = I915_READ(pp_off_reg); + pp_div = I915_READ(pp_div_reg); /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> @@ -2752,7 +2705,22 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, struct edp_power_seq *seq) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp_on, pp_off, pp_div; + u32 pp_on, pp_off, pp_div, port_sel = 0; + int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); + int pp_on_reg, pp_off_reg, pp_div_reg; + + if (HAS_PCH_SPLIT(dev)) { + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_div_reg = PCH_PP_DIVISOR; + } else { + pp_on_reg = PIPEA_PP_ON_DELAYS; + pp_off_reg = PIPEA_PP_OFF_DELAYS; + pp_div_reg = PIPEA_PP_DIVISOR; + } + + if (IS_VALLEYVIEW(dev)) + port_sel = I915_READ(pp_on_reg) & 0xc0000000; /* And finally store the new values in the power sequencer. */ pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | @@ -2761,8 +2729,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); /* Compute the divisor for the pp clock, simply match the Bspec * formula. */ - pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1) - << PP_REFERENCE_DIVIDER_SHIFT; + pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) << PANEL_POWER_CYCLE_DELAY_SHIFT); @@ -2770,19 +2737,21 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, * power sequencer any more. */ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { if (is_cpu_edp(intel_dp)) - pp_on |= PANEL_POWER_PORT_DP_A; + port_sel = PANEL_POWER_PORT_DP_A; else - pp_on |= PANEL_POWER_PORT_DP_D; + port_sel = PANEL_POWER_PORT_DP_D; } - I915_WRITE(PCH_PP_ON_DELAYS, pp_on); - I915_WRITE(PCH_PP_OFF_DELAYS, pp_off); - I915_WRITE(PCH_PP_DIVISOR, pp_div); + pp_on |= port_sel; + + I915_WRITE(pp_on_reg, pp_on); + I915_WRITE(pp_off_reg, pp_off); + I915_WRITE(pp_div_reg, pp_div); DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", - I915_READ(PCH_PP_ON_DELAYS), - I915_READ(PCH_PP_OFF_DELAYS), - I915_READ(PCH_PP_DIVISOR)); + I915_READ(pp_on_reg), + I915_READ(pp_off_reg), + I915_READ(pp_div_reg)); } void @@ -2829,7 +2798,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); - connector->polled = DRM_CONNECTOR_POLL_HPD; connector->interlace_allowed = true; connector->doublescan_allowed = 0; @@ -2844,27 +2812,46 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, else intel_connector->get_hw_state = intel_connector_get_hw_state; + intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; + if (HAS_DDI(dev)) { + switch (intel_dig_port->port) { + case PORT_A: + intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; + break; + case PORT_B: + intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; + break; + case PORT_C: + intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; + break; + case PORT_D: + intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; + break; + default: + BUG(); + } + } /* Set up the DDC bus. */ switch (port) { case PORT_A: + intel_encoder->hpd_pin = HPD_PORT_A; name = "DPDDC-A"; break; case PORT_B: - dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; + intel_encoder->hpd_pin = HPD_PORT_B; name = "DPDDC-B"; break; case PORT_C: - dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; + intel_encoder->hpd_pin = HPD_PORT_C; name = "DPDDC-C"; break; case PORT_D: - dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; + intel_encoder->hpd_pin = HPD_PORT_D; name = "DPDDC-D"; break; default: - WARN(1, "Invalid port %c\n", port_name(port)); - break; + BUG(); } if (is_edp(intel_dp)) @@ -2974,6 +2961,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); + intel_encoder->compute_config = intel_dp_compute_config; intel_encoder->enable = intel_enable_dp; intel_encoder->pre_enable = intel_pre_enable_dp; intel_encoder->disable = intel_disable_dp; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 07ebac6..b5b6d19 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -33,12 +33,21 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_dp_helper.h> +/** + * _wait_for - magic (register) wait macro + * + * Does the right thing for modeset paths when run under kdgb or similar atomic + * contexts. Note that it's important that we check the condition again after + * having timed out, since the timeout could be due to preemption or similar and + * we've never had a chance to check the condition before the timeout. + */ #define _wait_for(COND, MS, W) ({ \ - unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ + unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \ int ret__ = 0; \ while (!(COND)) { \ if (time_after(jiffies, timeout__)) { \ - ret__ = -ETIMEDOUT; \ + if (!(COND)) \ + ret__ = -ETIMEDOUT; \ break; \ } \ if (W && drm_can_sleep()) { \ @@ -50,21 +59,10 @@ ret__; \ }) -#define wait_for_atomic_us(COND, US) ({ \ - unsigned long timeout__ = jiffies + usecs_to_jiffies(US); \ - int ret__ = 0; \ - while (!(COND)) { \ - if (time_after(jiffies, timeout__)) { \ - ret__ = -ETIMEDOUT; \ - break; \ - } \ - cpu_relax(); \ - } \ - ret__; \ -}) - #define wait_for(COND, MS) _wait_for(COND, MS, 1) #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) +#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) @@ -101,34 +99,6 @@ #define INTEL_DVO_CHIP_TMDS 2 #define INTEL_DVO_CHIP_TVOUT 4 -/* drm_display_mode->private_flags */ -#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) -#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) -#define INTEL_MODE_DP_FORCE_6BPC (0x10) -/* This flag must be set by the encoder's mode_fixup if it changes the crtc - * timings in the mode to prevent the crtc fixup from overwriting them. - * Currently only lvds needs that. */ -#define INTEL_MODE_CRTC_TIMINGS_SET (0x20) -/* - * Set when limited 16-235 (as opposed to full 0-255) RGB color range is - * to be used. - */ -#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40) - -static inline void -intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, - int multiplier) -{ - mode->clock *= multiplier; - mode->private_flags |= multiplier; -} - -static inline int -intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) -{ - return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; -} - struct intel_framebuffer { struct drm_framebuffer base; struct drm_i915_gem_object *obj; @@ -158,9 +128,12 @@ struct intel_encoder { bool cloneable; bool connectors_active; void (*hot_plug)(struct intel_encoder *); + bool (*compute_config)(struct intel_encoder *, + struct intel_crtc_config *); void (*pre_pll_enable)(struct intel_encoder *); void (*pre_enable)(struct intel_encoder *); void (*enable)(struct intel_encoder *); + void (*mode_set)(struct intel_encoder *intel_encoder); void (*disable)(struct intel_encoder *); void (*post_disable)(struct intel_encoder *); /* Read out the current hw state of this connector, returning true if @@ -168,6 +141,7 @@ struct intel_encoder { * it is connected to in the pipe parameter. */ bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); int crtc_mask; + enum hpd_pin hpd_pin; }; struct intel_panel { @@ -197,13 +171,65 @@ struct intel_connector { /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ struct edid *edid; + + /* since POLL and HPD connectors may use the same HPD line keep the native + state of connector->polled in case hotplug storm detection changes it */ + u8 polled; +}; + +struct intel_crtc_config { + struct drm_display_mode requested_mode; + struct drm_display_mode adjusted_mode; + /* This flag must be set by the encoder's compute_config callback if it + * changes the crtc timings in the mode to prevent the crtc fixup from + * overwriting them. Currently only lvds needs that. */ + bool timings_set; + /* Whether to set up the PCH/FDI. Note that we never allow sharing + * between pch encoders and cpu encoders. */ + bool has_pch_encoder; + + /* CPU Transcoder for the pipe. Currently this can only differ from the + * pipe on Haswell (where we have a special eDP transcoder). */ + enum transcoder cpu_transcoder; + + /* + * Use reduced/limited/broadcast rbg range, compressing from the full + * range fed into the crtcs. + */ + bool limited_color_range; + + /* DP has a bunch of special case unfortunately, so mark the pipe + * accordingly. */ + bool has_dp_encoder; + bool dither; + + /* Controls for the clock computation, to override various stages. */ + bool clock_set; + + /* Settings for the intel dpll used on pretty much everything but + * haswell. */ + struct dpll { + unsigned n; + unsigned m1, m2; + unsigned p1, p2; + } dpll; + + int pipe_bpp; + struct intel_link_m_n dp_m_n; + /** + * This is currently used by DP and HDMI encoders since those can have a + * target pixel clock != the port link clock (which is currently stored + * in adjusted_mode->clock). + */ + int pixel_target_clock; + /* Used by SDVO (and if we ever fix it, HDMI). */ + unsigned pixel_multiplier; }; struct intel_crtc { struct drm_crtc base; enum pipe pipe; enum plane plane; - enum transcoder cpu_transcoder; u8 lut_r[256], lut_g[256], lut_b[256]; /* * Whether the crtc and the connected output pipeline is active. Implies @@ -230,7 +256,8 @@ struct intel_crtc { int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; bool cursor_visible; - unsigned int bpp; + + struct intel_crtc_config config; /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; @@ -242,11 +269,16 @@ struct intel_crtc { struct intel_plane { struct drm_plane base; + int plane; enum pipe pipe; struct drm_i915_gem_object *obj; bool can_scale; int max_downscale; u32 lut_r[1024], lut_g[1024], lut_b[1024]; + int crtc_x, crtc_y; + unsigned int crtc_w, crtc_h; + uint32_t src_x, src_y; + uint32_t src_w, src_h; void (*update_plane)(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, @@ -347,7 +379,7 @@ struct dip_infoframe { } __attribute__((packed)); struct intel_hdmi { - u32 sdvox_reg; + u32 hdmi_reg; int ddc_bus; uint32_t color_range; bool color_range_auto; @@ -366,6 +398,7 @@ struct intel_hdmi { struct intel_dp { uint32_t output_reg; + uint32_t aux_ch_ctl_reg; uint32_t DP; uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; bool has_audio; @@ -443,13 +476,12 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector) extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, - int sdvox_reg, enum port port); + int hdmi_reg, enum port port); extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); -extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); +extern bool intel_hdmi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config); extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); @@ -464,18 +496,14 @@ extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); -void -intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); extern void intel_dp_init_link_config(struct intel_dp *intel_dp); extern void intel_dp_start_link_train(struct intel_dp *intel_dp); extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); extern void intel_dp_encoder_destroy(struct drm_encoder *encoder); extern void intel_dp_check_link_status(struct intel_dp *intel_dp); -extern bool intel_dp_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); +extern bool intel_dp_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config); extern bool intel_dpd_is_edp(struct drm_device *dev); extern void ironlake_edp_backlight_on(struct intel_dp *intel_dp); extern void ironlake_edp_backlight_off(struct intel_dp *intel_dp); @@ -483,11 +511,8 @@ extern void ironlake_edp_panel_on(struct intel_dp *intel_dp); extern void ironlake_edp_panel_off(struct intel_dp *intel_dp); extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); -extern void intel_edp_link_config(struct intel_encoder *, int *, int *); -extern int intel_edp_target_clock(struct intel_encoder *, - struct drm_display_mode *mode); extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); -extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); +extern int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane); @@ -531,6 +556,7 @@ extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); extern void intel_modeset_check_state(struct drm_device *dev); +extern void intel_plane_restore(struct drm_plane *plane); static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) @@ -636,6 +662,10 @@ extern void intel_init_clock_gating(struct drm_device *dev); extern void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); +extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n); +extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n); extern void intel_prepare_ddi(struct drm_device *dev); extern void hsw_fdi_link_train(struct drm_crtc *crtc); extern void intel_ddi_init(struct drm_device *dev, enum port port); @@ -670,6 +700,7 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); +extern bool intel_using_power_well(struct drm_device *dev); extern void intel_init_power_well(struct drm_device *dev); extern void intel_set_power_well(struct drm_device *dev, bool enable); extern void intel_enable_gt_powersave(struct drm_device *dev); @@ -681,7 +712,7 @@ extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe); extern int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv); extern void intel_ddi_pll_init(struct drm_device *dev); -extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc); +extern void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc); extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder); extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); @@ -695,4 +726,6 @@ extern bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); +extern void intel_display_handle_reset(struct drm_device *dev); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 00e70db..cc70b16 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -448,6 +448,7 @@ void intel_dvo_init(struct drm_device *dev) const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; struct i2c_adapter *i2c; int gpio; + bool dvoinit; /* Allow the I2C driver info to specify the GPIO to be used in * special cases, but otherwise default to what's defined @@ -467,7 +468,17 @@ void intel_dvo_init(struct drm_device *dev) i2c = intel_gmbus_get_adapter(dev_priv, gpio); intel_dvo->dev = *dvo; - if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) + + /* GMBUS NAK handling seems to be unstable, hence let the + * transmitter detection run in bit banging mode for now. + */ + intel_gmbus_force_bit(i2c, true); + + dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c); + + intel_gmbus_force_bit(i2c, false); + + if (!dvoinit) continue; intel_encoder->type = INTEL_OUTPUT_DVO; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 981bdce..0e19e57 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -150,7 +150,8 @@ static int intelfb_create(struct drm_fb_helper *helper, } info->screen_size = size; -// memset(info->screen_base, 0, size); + /* This driver doesn't need a VT switch to restore the mode on resume */ + info->skip_vt_switch = true; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); @@ -227,7 +228,7 @@ int intel_fbdev_init(struct drm_device *dev) ifbdev->helper.funcs = &intel_fb_helper_funcs; ret = drm_fb_helper_init(dev, &ifbdev->helper, - dev_priv->num_pipe, + INTEL_INFO(dev)->num_pipes, INTELFB_CONN_LIMIT); if (ret) { kfree(ifbdev); @@ -282,6 +283,9 @@ void intel_fb_restore_mode(struct drm_device *dev) struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; + if (INTEL_INFO(dev)->num_pipes == 0) + return; + drm_modeset_lock_all(dev); ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index fa8ec4a..a905793 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -50,7 +50,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; - WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, + WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, "HDMI port enabled, expecting disabled\n"); } @@ -120,13 +120,14 @@ static u32 hsw_infoframe_enable(struct dip_infoframe *frame) } } -static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe) +static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, + enum transcoder cpu_transcoder) { switch (frame->type) { case DIP_TYPE_AVI: - return HSW_TVIDEO_DIP_AVI_DATA(pipe); + return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); case DIP_TYPE_SPD: - return HSW_TVIDEO_DIP_SPD_DATA(pipe); + return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); default: DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); return 0; @@ -293,8 +294,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, 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); - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); - u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe); + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); + u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder); unsigned int i, len = DIP_HEADER_SIZE + frame->len; u32 val = I915_READ(ctl_reg); @@ -332,6 +333,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, .ver = DIP_VERSION_AVI, @@ -342,7 +344,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; if (intel_hdmi->rgb_quant_range_selectable) { - if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + if (intel_crtc->config.limited_color_range) avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; else avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; @@ -568,7 +570,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); + u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); u32 val = I915_READ(reg); assert_hdmi_port_disabled(intel_hdmi); @@ -597,40 +599,40 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 sdvox; + u32 hdmi_val; - sdvox = SDVO_ENCODING_HDMI; - if (!HAS_PCH_SPLIT(dev)) - sdvox |= intel_hdmi->color_range; + hdmi_val = SDVO_ENCODING_HDMI; + if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) + hdmi_val |= intel_hdmi->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - sdvox |= SDVO_VSYNC_ACTIVE_HIGH; + hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - sdvox |= SDVO_HSYNC_ACTIVE_HIGH; + hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; - if (intel_crtc->bpp > 24) - sdvox |= COLOR_FORMAT_12bpc; + if (intel_crtc->config.pipe_bpp > 24) + hdmi_val |= HDMI_COLOR_FORMAT_12bpc; else - sdvox |= COLOR_FORMAT_8bpc; + hdmi_val |= SDVO_COLOR_FORMAT_8bpc; /* Required on CPT */ if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) - sdvox |= HDMI_MODE_SELECT; + hdmi_val |= HDMI_MODE_SELECT_HDMI; if (intel_hdmi->has_audio) { DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", pipe_name(intel_crtc->pipe)); - sdvox |= SDVO_AUDIO_ENABLE; - sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; + hdmi_val |= SDVO_AUDIO_ENABLE; + hdmi_val |= HDMI_MODE_SELECT_HDMI; intel_write_eld(encoder, adjusted_mode); } if (HAS_PCH_CPT(dev)) - sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); - else if (intel_crtc->pipe == PIPE_B) - sdvox |= SDVO_PIPE_B_SELECT; + hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); + else + hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe); - I915_WRITE(intel_hdmi->sdvox_reg, sdvox); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); + POSTING_READ(intel_hdmi->hdmi_reg); intel_hdmi->set_infoframes(encoder, adjusted_mode); } @@ -643,7 +645,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 tmp; - tmp = I915_READ(intel_hdmi->sdvox_reg); + tmp = I915_READ(intel_hdmi->hdmi_reg); if (!(tmp & SDVO_ENABLE)) return false; @@ -660,6 +662,7 @@ static void intel_enable_hdmi(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); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 temp; u32 enable_bits = SDVO_ENABLE; @@ -667,38 +670,32 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) if (intel_hdmi->has_audio) enable_bits |= SDVO_AUDIO_ENABLE; - temp = I915_READ(intel_hdmi->sdvox_reg); + temp = I915_READ(intel_hdmi->hdmi_reg); /* HW workaround for IBX, we need to move the port to transcoder A - * before disabling it. */ - if (HAS_PCH_IBX(dev)) { - struct drm_crtc *crtc = encoder->base.crtc; - int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; - - /* Restore the transcoder select bit. */ - if (pipe == PIPE_B) - enable_bits |= SDVO_PIPE_B_SELECT; - } + * before disabling it, so restore the transcoder select bit here. */ + if (HAS_PCH_IBX(dev)) + enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); /* HW workaround, need to toggle enable bit off and on for 12bpc, but * we do this anyway which shows more stable in testing. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->hdmi_reg); } temp |= enable_bits; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* HW workaround, need to write this twice for issue that may result * in first write getting masked. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); } } @@ -710,7 +707,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) u32 temp; u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; - temp = I915_READ(intel_hdmi->sdvox_reg); + temp = I915_READ(intel_hdmi->hdmi_reg); /* HW workaround for IBX, we need to move the port to transcoder A * before disabling it. */ @@ -720,12 +717,12 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) if (temp & SDVO_PIPE_B_SELECT) { temp &= ~SDVO_PIPE_B_SELECT; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* Again we need to write this twice. */ - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* Transcoder selection bits only update * effectively on vblank. */ @@ -740,21 +737,21 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) * we do this anyway which shows more stable in testing. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->hdmi_reg); } temp &= ~enable_bits; - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); /* HW workaround, need to write this twice for issue that may result * in first write getting masked. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->sdvox_reg, temp); - POSTING_READ(intel_hdmi->sdvox_reg); + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); } } @@ -772,23 +769,40 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool intel_hdmi_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + struct drm_device *dev = encoder->base.dev; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; if (intel_hdmi->color_range_auto) { /* See CEA-861-E - 5.1 Default Encoding Parameters */ if (intel_hdmi->has_hdmi_sink && drm_match_cea_mode(adjusted_mode) > 1) - intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; else intel_hdmi->color_range = 0; } if (intel_hdmi->color_range) - adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + pipe_config->limited_color_range = true; + + if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) + pipe_config->has_pch_encoder = true; + + /* + * HDMI is either 12 or 8, so if the display lets 10bpc sneak + * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi + * outputs. + */ + if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) { + DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); + pipe_config->pipe_bpp = 12*3; + } else { + DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); + pipe_config->pipe_bpp = 8*3; + } return true; } @@ -906,6 +920,9 @@ intel_hdmi_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_hdmi->color_range_auto; + uint32_t old_range = intel_hdmi->color_range; + switch (val) { case INTEL_BROADCAST_RGB_AUTO: intel_hdmi->color_range_auto = true; @@ -916,11 +933,16 @@ intel_hdmi_set_property(struct drm_connector *connector, break; case INTEL_BROADCAST_RGB_LIMITED: intel_hdmi->color_range_auto = false; - intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; break; default: return -EINVAL; } + + if (old_auto == intel_hdmi->color_range_auto && + old_range == intel_hdmi->color_range) + return 0; + goto done; } @@ -941,7 +963,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector) } static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { - .mode_fixup = intel_hdmi_mode_fixup, .mode_set = intel_hdmi_mode_set, }; @@ -985,36 +1006,36 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, DRM_MODE_CONNECTOR_HDMIA); drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); - connector->polled = DRM_CONNECTOR_POLL_HPD; connector->interlace_allowed = 1; connector->doublescan_allowed = 0; switch (port) { case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; + intel_encoder->hpd_pin = HPD_PORT_B; break; case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; + intel_encoder->hpd_pin = HPD_PORT_C; break; case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; + intel_encoder->hpd_pin = HPD_PORT_D; break; case PORT_A: + intel_encoder->hpd_pin = HPD_PORT_A; /* Internal port only for eDP. */ default: BUG(); } - if (!HAS_PCH_SPLIT(dev)) { - intel_hdmi->write_infoframe = g4x_write_infoframe; - intel_hdmi->set_infoframes = g4x_set_infoframes; - } else if (IS_VALLEYVIEW(dev)) { + if (IS_VALLEYVIEW(dev)) { intel_hdmi->write_infoframe = vlv_write_infoframe; intel_hdmi->set_infoframes = vlv_set_infoframes; - } else if (IS_HASWELL(dev)) { + } else if (!HAS_PCH_SPLIT(dev)) { + intel_hdmi->write_infoframe = g4x_write_infoframe; + intel_hdmi->set_infoframes = g4x_set_infoframes; + } else if (HAS_DDI(dev)) { intel_hdmi->write_infoframe = hsw_write_infoframe; intel_hdmi->set_infoframes = hsw_set_infoframes; } else if (HAS_PCH_IBX(dev)) { @@ -1045,7 +1066,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, } } -void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) +void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) { struct intel_digital_port *intel_dig_port; struct intel_encoder *intel_encoder; @@ -1069,6 +1090,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); + intel_encoder->compute_config = intel_hdmi_compute_config; intel_encoder->enable = intel_enable_hdmi; intel_encoder->disable = intel_disable_hdmi; intel_encoder->get_hw_state = intel_hdmi_get_hw_state; @@ -1078,7 +1100,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) intel_encoder->cloneable = false; intel_dig_port->port = port; - intel_dig_port->hdmi.sdvox_reg = sdvox_reg; + intel_dig_port->hdmi.hdmi_reg = hdmi_reg; intel_dig_port->dp.output_reg = 0; intel_hdmi_init_connector(intel_dig_port, intel_connector); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index ef4744e..5d24503 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -522,7 +522,9 @@ int intel_setup_gmbus(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_NOP(dev)) + return 0; + else if (HAS_PCH_SPLIT(dev)) dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; else if (IS_VALLEYVIEW(dev)) dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3d1d974..f36f1ba 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -261,8 +261,6 @@ centre_horizontally(struct drm_display_mode *mode, mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; - - mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; } static void @@ -284,8 +282,6 @@ centre_vertically(struct drm_display_mode *mode, mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; - - mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; } static inline u32 panel_fitter_scaling(u32 source, u32 target) @@ -301,17 +297,20 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target) return (FACTOR * ratio + FACTOR/2) / FACTOR; } -static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, + struct intel_crtc_config *pipe_config) { - struct drm_device *dev = encoder->dev; + struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); + struct intel_lvds_encoder *lvds_encoder = + to_lvds_encoder(&intel_encoder->base); struct intel_connector *intel_connector = &lvds_encoder->attached_connector->base; + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; + unsigned int lvds_bpp; int pipe; /* Should never happen!! */ @@ -323,6 +322,17 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, if (intel_encoder_check_is_cloned(&lvds_encoder->base)) return false; + if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) == + LVDS_A3_POWER_UP) + lvds_bpp = 8*3; + else + lvds_bpp = 6*3; + + if (lvds_bpp != pipe_config->pipe_bpp) { + DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", + pipe_config->pipe_bpp, lvds_bpp); + pipe_config->pipe_bpp = lvds_bpp; + } /* * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, @@ -333,6 +343,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, adjusted_mode); if (HAS_PCH_SPLIT(dev)) { + pipe_config->has_pch_encoder = true; + intel_pch_panel_fitting(dev, intel_connector->panel.fitting_mode, mode, adjusted_mode); @@ -359,6 +371,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, I915_WRITE(BCLRPAT(pipe), 0); drm_mode_set_crtcinfo(adjusted_mode, 0); + pipe_config->timings_set = true; switch (intel_connector->panel.fitting_mode) { case DRM_MODE_SCALE_CENTER: @@ -618,7 +631,6 @@ static void intel_lvds_destroy(struct drm_connector *connector) if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) kfree(lvds_connector->base.edid); - intel_panel_destroy_backlight(connector->dev); intel_panel_fini(&lvds_connector->base.panel); drm_sysfs_connector_remove(connector); @@ -661,7 +673,6 @@ static int intel_lvds_set_property(struct drm_connector *connector, } static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { - .mode_fixup = intel_lvds_mode_fixup, .mode_set = intel_lvds_mode_set, }; @@ -850,6 +861,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Fujitsu Esprimo Q900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"), + }, + }, { } /* terminating entry */ }; @@ -1019,12 +1038,15 @@ static bool intel_lvds_supported(struct drm_device *dev) { /* With the introduction of the PCH we gained a dedicated * LVDS presence pin, use it. */ - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) return true; /* Otherwise LVDS was only attached to mobile products, * except for the inglorious 830gm */ - return IS_MOBILE(dev) && !IS_I830(dev); + if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) + return true; + + return false; } /** @@ -1102,6 +1124,7 @@ bool intel_lvds_init(struct drm_device *dev) intel_encoder->enable = intel_enable_lvds; intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; + intel_encoder->compute_config = intel_lvds_compute_config; intel_encoder->disable = intel_disable_lvds; intel_encoder->get_hw_state = intel_lvds_get_hw_state; intel_connector->get_hw_state = intel_connector_get_hw_state; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index bee8cb6..eb5e6e9 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -286,8 +286,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level) { struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->backlight_level = level; - if (dev_priv->backlight_enabled) + dev_priv->backlight.level = level; + if (dev_priv->backlight.device) + dev_priv->backlight.device->props.brightness = level; + + if (dev_priv->backlight.enabled) intel_panel_actually_set_backlight(dev, level); } @@ -295,7 +298,7 @@ void intel_panel_disable_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->backlight_enabled = false; + dev_priv->backlight.enabled = false; intel_panel_actually_set_backlight(dev, 0); if (INTEL_INFO(dev)->gen >= 4) { @@ -318,8 +321,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight_level == 0) - dev_priv->backlight_level = intel_panel_get_max_backlight(dev); + if (dev_priv->backlight.level == 0) { + dev_priv->backlight.level = intel_panel_get_max_backlight(dev); + if (dev_priv->backlight.device) + dev_priv->backlight.device->props.brightness = + dev_priv->backlight.level; + } if (INTEL_INFO(dev)->gen >= 4) { uint32_t reg, tmp; @@ -335,7 +342,7 @@ void intel_panel_enable_backlight(struct drm_device *dev, if (tmp & BLM_PWM_ENABLE) goto set_level; - if (dev_priv->num_pipe == 3) + if (INTEL_INFO(dev)->num_pipes == 3) tmp &= ~BLM_PIPE_SELECT_IVB; else tmp &= ~BLM_PIPE_SELECT; @@ -360,16 +367,16 @@ set_level: * 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, dev_priv->backlight_level); + dev_priv->backlight.enabled = true; + intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); } static void intel_panel_init_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->backlight_level = intel_panel_get_backlight(dev); - dev_priv->backlight_enabled = dev_priv->backlight_level != 0; + dev_priv->backlight.level = intel_panel_get_backlight(dev); + dev_priv->backlight.enabled = dev_priv->backlight.level != 0; } enum drm_connector_status @@ -405,8 +412,7 @@ static int intel_panel_update_status(struct backlight_device *bd) static int intel_panel_get_brightness(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); - struct drm_i915_private *dev_priv = dev->dev_private; - return dev_priv->backlight_level; + return intel_panel_get_backlight(dev); } static const struct backlight_ops intel_panel_bl_ops = { @@ -422,33 +428,38 @@ int intel_panel_setup_backlight(struct drm_connector *connector) intel_panel_init_backlight(dev); + if (WARN_ON(dev_priv->backlight.device)) + return -ENODEV; + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; + props.brightness = dev_priv->backlight.level; props.max_brightness = _intel_panel_get_max_backlight(dev); if (props.max_brightness == 0) { DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; } - dev_priv->backlight = + dev_priv->backlight.device = backlight_device_register("intel_backlight", &connector->kdev, dev, &intel_panel_bl_ops, &props); - if (IS_ERR(dev_priv->backlight)) { + if (IS_ERR(dev_priv->backlight.device)) { DRM_ERROR("Failed to register backlight: %ld\n", - PTR_ERR(dev_priv->backlight)); - dev_priv->backlight = NULL; + PTR_ERR(dev_priv->backlight.device)); + dev_priv->backlight.device = NULL; return -ENODEV; } - dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev); return 0; } void intel_panel_destroy_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight) - backlight_device_unregister(dev_priv->backlight); + if (dev_priv->backlight.device) { + backlight_device_unregister(dev_priv->backlight.device); + dev_priv->backlight.device = NULL; + } } #else int intel_panel_setup_backlight(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index adca007..de3b0dc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2460,10 +2460,14 @@ void gen6_set_rps(struct drm_device *dev, u8 val) if (val == dev_priv->rps.cur_delay) return; - I915_WRITE(GEN6_RPNSWREQ, - GEN6_FREQUENCY(val) | - GEN6_OFFSET(0) | - GEN6_AGGRESSIVE_TURBO); + if (IS_HASWELL(dev)) + I915_WRITE(GEN6_RPNSWREQ, + HSW_FREQUENCY(val)); + else + I915_WRITE(GEN6_RPNSWREQ, + GEN6_FREQUENCY(val) | + GEN6_OFFSET(0) | + GEN6_AGGRESSIVE_TURBO); /* Make sure we continue to get interrupts * until we hit the minimum or maximum frequencies. @@ -2554,8 +2558,8 @@ static void gen6_enable_rps(struct drm_device *dev) rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - /* In units of 100MHz */ - dev_priv->rps.max_delay = rp_state_cap & 0xff; + /* In units of 50MHz */ + dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff; dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16; dev_priv->rps.cur_delay = 0; @@ -2601,12 +2605,19 @@ static void gen6_enable_rps(struct drm_device *dev) GEN6_RC_CTL_EI_MODE(1) | GEN6_RC_CTL_HW_ENABLE); - I915_WRITE(GEN6_RPNSWREQ, - GEN6_FREQUENCY(10) | - GEN6_OFFSET(0) | - GEN6_AGGRESSIVE_TURBO); - I915_WRITE(GEN6_RC_VIDEO_FREQ, - GEN6_FREQUENCY(12)); + if (IS_HASWELL(dev)) { + I915_WRITE(GEN6_RPNSWREQ, + HSW_FREQUENCY(10)); + I915_WRITE(GEN6_RC_VIDEO_FREQ, + HSW_FREQUENCY(12)); + } else { + I915_WRITE(GEN6_RPNSWREQ, + GEN6_FREQUENCY(10) | + GEN6_OFFSET(0) | + GEN6_AGGRESSIVE_TURBO); + I915_WRITE(GEN6_RC_VIDEO_FREQ, + GEN6_FREQUENCY(12)); + } I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, @@ -2631,9 +2642,11 @@ static void gen6_enable_rps(struct drm_device *dev) if (!ret) { pcu_mbox = 0; ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox); - if (ret && pcu_mbox & (1<<31)) { /* OC supported */ - dev_priv->rps.max_delay = pcu_mbox & 0xff; - DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); + if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */ + DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n", + (dev_priv->rps.max_delay & 0xff) * 50, + (pcu_mbox & 0xff) * 50); + dev_priv->rps.hw_max = pcu_mbox & 0xff; } } else { DRM_DEBUG_DRIVER("Failed to set the min frequency\n"); @@ -2671,8 +2684,8 @@ static void gen6_update_ring_freq(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int min_freq = 15; - int gpu_freq; - unsigned int ia_freq, max_ia_freq; + unsigned int gpu_freq; + unsigned int max_ia_freq, min_ring_freq; int scaling_factor = 180; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); @@ -2688,6 +2701,10 @@ static void gen6_update_ring_freq(struct drm_device *dev) /* Convert from kHz to MHz */ max_ia_freq /= 1000; + min_ring_freq = I915_READ(MCHBAR_MIRROR_BASE_SNB + DCLK); + /* convert DDR frequency from units of 133.3MHz to bandwidth */ + min_ring_freq = (2 * 4 * min_ring_freq + 2) / 3; + /* * For each potential GPU frequency, load a ring frequency we'd like * to use for memory access. We do this by specifying the IA frequency @@ -2696,21 +2713,32 @@ static void gen6_update_ring_freq(struct drm_device *dev) for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay; gpu_freq--) { int diff = dev_priv->rps.max_delay - gpu_freq; - - /* - * For GPU frequencies less than 750MHz, just use the lowest - * ring freq. - */ - if (gpu_freq < min_freq) - ia_freq = 800; - else - ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); - ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); - ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT; + unsigned int ia_freq = 0, ring_freq = 0; + + if (IS_HASWELL(dev)) { + ring_freq = (gpu_freq * 5 + 3) / 4; + ring_freq = max(min_ring_freq, ring_freq); + /* leave ia_freq as the default, chosen by cpufreq */ + } else { + /* On older processors, there is no separate ring + * clock domain, so in order to boost the bandwidth + * of the ring, we need to upclock the CPU (ia_freq). + * + * For GPU frequencies less than 750MHz, + * just use the lowest ring freq. + */ + if (gpu_freq < min_freq) + ia_freq = 800; + else + ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); + ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); + } sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, - ia_freq | gpu_freq); + ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT | + ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT | + gpu_freq); } } @@ -2821,7 +2849,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) ret = intel_ring_idle(ring); dev_priv->mm.interruptible = was_interruptible; if (ret) { - DRM_ERROR("failed to enable ironlake power power savings\n"); + DRM_ERROR("failed to enable ironlake power savings\n"); ironlake_teardown_rc6(dev); return; } @@ -3562,6 +3590,7 @@ static void cpt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; + uint32_t val; /* * On Ibex Peak and Cougar Point, we need to disable clock @@ -3574,8 +3603,17 @@ static void cpt_init_clock_gating(struct drm_device *dev) /* The below fixes the weird display corruption, a few pixels shifted * downward, on (only) LVDS of some HP laptops with IVY. */ - for_each_pipe(pipe) - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_CHICKEN2_TIMING_OVERRIDE); + for_each_pipe(pipe) { + val = I915_READ(TRANS_CHICKEN2(pipe)); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; + if (dev_priv->fdi_rx_polarity_inverted) + val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; + val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; + val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; + val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH; + I915_WRITE(TRANS_CHICKEN2(pipe), val); + } /* WADP0ClockGatingDisable */ for_each_pipe(pipe) { I915_WRITE(TRANS_CHICKEN1(pipe), @@ -3768,6 +3806,9 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); + /* WaSwitchSolVfFArbitrationPriority */ + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); + /* XXX: This is a workaround for early silicon revisions and should be * removed later. */ @@ -3874,7 +3915,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) snpcr |= GEN6_MBC_SNPCR_MED; I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); - cpt_init_clock_gating(dev); + if (!HAS_PCH_NOP(dev)) + cpt_init_clock_gating(dev); gen6_check_mch_setup(dev); } @@ -3899,8 +3941,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); + /* WaDisablePSDDualDispatchEnable */ I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, - _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | + GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, @@ -3968,24 +4012,20 @@ static void valleyview_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); /* - * On ValleyView, the GUnit needs to signal the GT - * when flip and other events complete. So enable - * all the GUnit->GT interrupts here - */ - I915_WRITE(VLV_DPFLIPSTAT, PIPEB_LINE_COMPARE_INT_EN | - PIPEB_HLINE_INT_EN | PIPEB_VBLANK_INT_EN | - SPRITED_FLIPDONE_INT_EN | SPRITEC_FLIPDONE_INT_EN | - PLANEB_FLIPDONE_INT_EN | PIPEA_LINE_COMPARE_INT_EN | - PIPEA_HLINE_INT_EN | PIPEA_VBLANK_INT_EN | - SPRITEB_FLIPDONE_INT_EN | SPRITEA_FLIPDONE_INT_EN | - PLANEA_FLIPDONE_INT_EN); - - /* * WaDisableVLVClockGating_VBIIssue * Disable clock gating on th GCFG unit to prevent a delay * in the reporting of vblank events. */ - I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS); + I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff); + + /* Conservative clock gating settings for now */ + I915_WRITE(0x9400, 0xffffffff); + I915_WRITE(0x9404, 0xffffffff); + I915_WRITE(0x9408, 0xffffffff); + I915_WRITE(0x940c, 0xffffffff); + I915_WRITE(0x9410, 0xffffffff); + I915_WRITE(0x9414, 0xffffffff); + I915_WRITE(0x9418, 0xffffffff); } static void g4x_init_clock_gating(struct drm_device *dev) @@ -4070,13 +4110,29 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } +/** + * 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. + */ +bool intel_using_power_well(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_HASWELL(dev)) + return I915_READ(HSW_PWR_WELL_DRIVER) == + (HSW_PWR_WELL_ENABLE | HSW_PWR_WELL_STATE); + else + return true; +} + void intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; uint32_t tmp; - if (!IS_HASWELL(dev)) + if (!HAS_POWER_WELL(dev)) return; if (!i915_disable_power_well && !enable) @@ -4114,7 +4170,7 @@ void intel_init_power_well(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_HASWELL(dev)) + if (!HAS_POWER_WELL(dev)) return; /* For now, we need the power well to be always enabled. */ @@ -4176,7 +4232,6 @@ void intel_init_pm(struct drm_device *dev) } dev_priv->display.init_clock_gating = gen6_init_clock_gating; } else if (IS_IVYBRIDGE(dev)) { - /* FIXME: detect B0+ stepping and use auto training */ if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = ivybridge_update_wm; dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; @@ -4274,21 +4329,14 @@ static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { - u32 forcewake_ack; - - if (IS_HASWELL(dev_priv->dev)) - forcewake_ack = FORCEWAKE_ACK_HSW; - else - forcewake_ack = FORCEWAKE_ACK; - - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); - I915_WRITE_NOTRACE(FORCEWAKE, FORCEWAKE_KERNEL); + I915_WRITE_NOTRACE(FORCEWAKE, 1); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1), FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); @@ -4311,7 +4359,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) else forcewake_ack = FORCEWAKE_MT_ACK; - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, + if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); @@ -4319,7 +4367,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) /* something from same cacheline, but !FORCEWAKE_MT */ POSTING_READ(ECOBUS); - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), + if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL), FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); @@ -4409,15 +4457,22 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) static void vlv_force_wake_get(struct drm_i915_private *dev_priv) { - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0, + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); + I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), FORCEWAKE_ACK_TIMEOUT_MS)) - DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); + DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); + + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_MEDIA_VLV) & + FORCEWAKE_KERNEL), + FORCEWAKE_ACK_TIMEOUT_MS)) + DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); __gen6_gt_wait_for_thread_c0(dev_priv); } @@ -4425,8 +4480,9 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) static void vlv_force_wake_put(struct drm_i915_private *dev_priv) { I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); - /* something from same cacheline, but !FORCEWAKE_VLV */ - POSTING_READ(FORCEWAKE_ACK_VLV); + I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); + /* The below doubles as a POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); } @@ -4511,3 +4567,56 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) return 0; } + +static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, + u8 addr, u32 *val) +{ + u32 cmd, devfn, port, be, bar; + + bar = 0; + be = 0xf; + port = IOSF_PORT_PUNIT; + devfn = PCI_DEVFN(2, 0); + + cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | + (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | + (bar << IOSF_BAR_SHIFT); + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) { + DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n", + opcode == PUNIT_OPCODE_REG_READ ? + "read" : "write"); + return -EAGAIN; + } + + I915_WRITE(VLV_IOSF_ADDR, addr); + if (opcode == PUNIT_OPCODE_REG_WRITE) + I915_WRITE(VLV_IOSF_DATA, *val); + I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); + + if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, + 500)) { + DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", + opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", + addr); + return -ETIMEDOUT; + } + + if (opcode == PUNIT_OPCODE_REG_READ) + *val = I915_READ(VLV_IOSF_DATA); + I915_WRITE(VLV_IOSF_DATA, 0); + + return 0; +} + +int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +{ + return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_READ, addr, val); +} + +int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) +{ + return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_WRITE, addr, &val); +} diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 78413ec..d154284 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -246,11 +246,11 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) return; } - if (intel_sdvo->sdvo_reg == SDVOB) { - cval = I915_READ(SDVOC); - } else { - bval = I915_READ(SDVOB); - } + if (intel_sdvo->sdvo_reg == GEN3_SDVOB) + cval = I915_READ(GEN3_SDVOC); + else + bval = I915_READ(GEN3_SDVOB); + /* * Write the registers twice for luck. Sometimes, * writing them only once doesn't appear to 'stick'. @@ -258,10 +258,10 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) */ for (i = 0; i < 2; i++) { - I915_WRITE(SDVOB, bval); - I915_READ(SDVOB); - I915_WRITE(SDVOC, cval); - I915_READ(SDVOC); + I915_WRITE(GEN3_SDVOB, bval); + I915_READ(GEN3_SDVOB); + I915_WRITE(GEN3_SDVOC, cval); + I915_READ(GEN3_SDVOC); } } @@ -788,7 +788,6 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, v_sync_offset = mode->vsync_start - mode->vdisplay; mode_clock = mode->clock; - mode_clock /= intel_mode_get_pixel_multiplier(mode) ?: 1; mode_clock /= 10; dtd->part1.clock = mode_clock; @@ -957,14 +956,17 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, .len = DIP_LEN_AVI, }; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_sdvo->base.base.crtc); if (intel_sdvo->rgb_quant_range_selectable) { - if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + if (intel_crtc->config.limited_color_range) avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; else avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; } + avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); + intel_dip_infoframe_csum(&avi_if); /* sdvo spec says that the ecc is handled by the hw, and it looks like @@ -1039,12 +1041,18 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, return true; } -static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool intel_sdvo_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { - struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); - int multiplier; + struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + struct drm_display_mode *mode = &pipe_config->requested_mode; + + DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n"); + pipe_config->pipe_bpp = 8*3; + + if (HAS_PCH_SPLIT(encoder->base.dev)) + pipe_config->has_pch_encoder = true; /* We need to construct preferred input timings based on our * output timings. To do that, we have to set the output @@ -1071,37 +1079,40 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, /* Make the CRTC code factor in the SDVO pixel multiplier. The * SDVO device will factor out the multiplier during mode_set. */ - multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); - intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + pipe_config->pixel_multiplier = + intel_sdvo_get_pixel_multiplier(adjusted_mode); + adjusted_mode->clock *= pipe_config->pixel_multiplier; if (intel_sdvo->color_range_auto) { /* See CEA-861-E - 5.1 Default Encoding Parameters */ + /* FIXME: This bit is only valid when using TMDS encoding and 8 + * bit per color mode. */ if (intel_sdvo->has_hdmi_monitor && drm_match_cea_mode(adjusted_mode) > 1) - intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; else intel_sdvo->color_range = 0; } if (intel_sdvo->color_range) - adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + pipe_config->limited_color_range = true; return true; } -static void intel_sdvo_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder) { - struct drm_device *dev = encoder->dev; + struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = encoder->crtc; + struct drm_crtc *crtc = intel_encoder->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; + struct intel_sdvo *intel_sdvo = to_intel_sdvo(&intel_encoder->base); u32 sdvox; struct intel_sdvo_in_out_map in_out; struct intel_sdvo_dtd input_dtd, output_dtd; - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); int rate; if (!mode) @@ -1161,7 +1172,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, DRM_INFO("Setting input timings on %s failed\n", SDVO_NAME(intel_sdvo)); - switch (pixel_multiplier) { + switch (intel_crtc->config.pixel_multiplier) { default: case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; @@ -1182,10 +1193,10 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } else { sdvox = I915_READ(intel_sdvo->sdvo_reg); switch (intel_sdvo->sdvo_reg) { - case SDVOB: + case GEN3_SDVOB: sdvox &= SDVOB_PRESERVE_MASK; break; - case SDVOC: + case GEN3_SDVOC: sdvox &= SDVOC_PRESERVE_MASK; break; } @@ -1193,9 +1204,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } if (INTEL_PCH_TYPE(dev) >= PCH_CPT) - sdvox |= TRANSCODER_CPT(intel_crtc->pipe); + sdvox |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); else - sdvox |= TRANSCODER(intel_crtc->pipe); + sdvox |= SDVO_PIPE_SEL(intel_crtc->pipe); if (intel_sdvo->has_hdmi_audio) sdvox |= SDVO_AUDIO_ENABLE; @@ -1205,7 +1216,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { /* done in crtc_mode_set as it lives inside the dpll register */ } else { - sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT; + sdvox |= (intel_crtc->config.pixel_multiplier - 1) + << SDVO_PORT_MULTIPLY_SHIFT; } if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL && @@ -1235,11 +1247,13 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); + u16 active_outputs; u32 tmp; tmp = I915_READ(intel_sdvo->sdvo_reg); + intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); - if (!(tmp & SDVO_ENABLE)) + if (!(tmp & SDVO_ENABLE) && (active_outputs == 0)) return false; if (HAS_PCH_CPT(dev)) @@ -1305,15 +1319,9 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) temp = I915_READ(intel_sdvo->sdvo_reg); if ((temp & SDVO_ENABLE) == 0) { /* HW workaround for IBX, we need to move the port - * to transcoder A before disabling it. */ - if (HAS_PCH_IBX(dev)) { - struct drm_crtc *crtc = encoder->base.crtc; - int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; - - /* Restore the transcoder select bit. */ - if (pipe == PIPE_B) - temp |= SDVO_PIPE_B_SELECT; - } + * to transcoder A before disabling it, so restore it here. */ + if (HAS_PCH_IBX(dev)) + temp |= SDVO_PIPE_SEL(intel_crtc->pipe); intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); } @@ -1922,6 +1930,9 @@ intel_sdvo_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { + bool old_auto = intel_sdvo->color_range_auto; + uint32_t old_range = intel_sdvo->color_range; + switch (val) { case INTEL_BROADCAST_RGB_AUTO: intel_sdvo->color_range_auto = true; @@ -1932,11 +1943,18 @@ intel_sdvo_set_property(struct drm_connector *connector, break; case INTEL_BROADCAST_RGB_LIMITED: intel_sdvo->color_range_auto = false; - intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + /* FIXME: this bit is only valid when using TMDS + * encoding and 8 bit per color mode. */ + intel_sdvo->color_range = HDMI_COLOR_RANGE_16_235; break; default: return -EINVAL; } + + if (old_auto == intel_sdvo->color_range_auto && + old_range == intel_sdvo->color_range) + return 0; + goto done; } @@ -2040,11 +2058,6 @@ done: #undef CHECK_PROPERTY } -static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { - .mode_fixup = intel_sdvo_mode_fixup, - .mode_set = intel_sdvo_mode_set, -}; - static const struct drm_connector_funcs intel_sdvo_connector_funcs = { .dpms = intel_sdvo_dpms, .detect = intel_sdvo_detect, @@ -2269,7 +2282,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) connector = &intel_connector->base; if (intel_sdvo_get_hotplug_support(intel_sdvo) & intel_sdvo_connector->output_flag) { - connector->polled = DRM_CONNECTOR_POLL_HPD; intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag; /* Some SDVO devices have one-shot hotplug interrupts. * Ensure that they get re-enabled when an interrupt happens. @@ -2277,7 +2289,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_encoder->hot_plug = intel_sdvo_enable_hotplug; intel_sdvo_enable_hotplug(intel_encoder); } else { - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; } encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; @@ -2346,7 +2358,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; @@ -2739,7 +2751,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) struct intel_sdvo *intel_sdvo; u32 hotplug_mask; int i; - intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); if (!intel_sdvo) return false; @@ -2779,9 +2790,15 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; } - drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); + /* Only enable the hotplug irq if we need it, to work around noisy + * hotplug lines. + */ + if (intel_sdvo->hotplug_active) + intel_encoder->hpd_pin = HPD_SDVO_B ? HPD_SDVO_B : HPD_SDVO_C; + intel_encoder->compute_config = intel_sdvo_compute_config; intel_encoder->disable = intel_disable_sdvo; + intel_encoder->mode_set = intel_sdvo_mode_set; intel_encoder->enable = intel_enable_sdvo; intel_encoder->get_hw_state = intel_sdvo_get_hw_state; @@ -2807,12 +2824,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) */ intel_sdvo->base.cloneable = false; - /* Only enable the hotplug irq if we need it, to work around noisy - * hotplug lines. - */ - if (intel_sdvo->hotplug_active) - dev_priv->hotplug_supported_mask |= hotplug_mask; - intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 1b6eb76..c7d25c5 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -37,6 +37,174 @@ #include "i915_drv.h" static void +vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t x, uint32_t y, + uint32_t src_w, uint32_t src_h) +{ + struct drm_device *dev = dplane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(dplane); + int pipe = intel_plane->pipe; + int plane = intel_plane->plane; + u32 sprctl; + unsigned long sprsurf_offset, linear_offset; + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + + sprctl = I915_READ(SPCNTR(pipe, plane)); + + /* Mask out pixel format bits in case we change it */ + sprctl &= ~SP_PIXFORMAT_MASK; + sprctl &= ~SP_YUV_BYTE_ORDER_MASK; + sprctl &= ~SP_TILED; + + switch (fb->pixel_format) { + case DRM_FORMAT_YUYV: + sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV; + break; + case DRM_FORMAT_YVYU: + sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU; + break; + case DRM_FORMAT_UYVY: + sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY; + break; + case DRM_FORMAT_VYUY: + sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY; + break; + case DRM_FORMAT_RGB565: + sprctl |= SP_FORMAT_BGR565; + break; + case DRM_FORMAT_XRGB8888: + sprctl |= SP_FORMAT_BGRX8888; + break; + case DRM_FORMAT_ARGB8888: + sprctl |= SP_FORMAT_BGRA8888; + break; + case DRM_FORMAT_XBGR2101010: + sprctl |= SP_FORMAT_RGBX1010102; + break; + case DRM_FORMAT_ABGR2101010: + sprctl |= SP_FORMAT_RGBA1010102; + break; + case DRM_FORMAT_XBGR8888: + sprctl |= SP_FORMAT_RGBX8888; + break; + case DRM_FORMAT_ABGR8888: + sprctl |= SP_FORMAT_RGBA8888; + break; + default: + /* + * If we get here one of the upper layers failed to filter + * out the unsupported plane formats + */ + BUG(); + break; + } + + if (obj->tiling_mode != I915_TILING_NONE) + sprctl |= SP_TILED; + + sprctl |= SP_ENABLE; + + /* Sizes are 0 based */ + src_w--; + src_h--; + crtc_w--; + crtc_h--; + + intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + + I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); + I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); + + linear_offset = y * fb->pitches[0] + x * pixel_size; + sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, + obj->tiling_mode, + pixel_size, + fb->pitches[0]); + linear_offset -= sprsurf_offset; + + if (obj->tiling_mode != I915_TILING_NONE) + I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x); + else + I915_WRITE(SPLINOFF(pipe, plane), linear_offset); + + I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); + I915_WRITE(SPCNTR(pipe, plane), sprctl); + I915_MODIFY_DISPBASE(SPSURF(pipe, plane), obj->gtt_offset + + sprsurf_offset); + POSTING_READ(SPSURF(pipe, plane)); +} + +static void +vlv_disable_plane(struct drm_plane *dplane) +{ + struct drm_device *dev = dplane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(dplane); + int pipe = intel_plane->pipe; + int plane = intel_plane->plane; + + I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & + ~SP_ENABLE); + /* Activate double buffered register update */ + I915_MODIFY_DISPBASE(SPSURF(pipe, plane), 0); + POSTING_READ(SPSURF(pipe, plane)); +} + +static int +vlv_update_colorkey(struct drm_plane *dplane, + struct drm_intel_sprite_colorkey *key) +{ + struct drm_device *dev = dplane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(dplane); + int pipe = intel_plane->pipe; + int plane = intel_plane->plane; + u32 sprctl; + + if (key->flags & I915_SET_COLORKEY_DESTINATION) + return -EINVAL; + + I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); + I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); + I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask); + + sprctl = I915_READ(SPCNTR(pipe, plane)); + sprctl &= ~SP_SOURCE_KEY; + if (key->flags & I915_SET_COLORKEY_SOURCE) + sprctl |= SP_SOURCE_KEY; + I915_WRITE(SPCNTR(pipe, plane), sprctl); + + POSTING_READ(SPKEYMSK(pipe, plane)); + + return 0; +} + +static void +vlv_get_colorkey(struct drm_plane *dplane, + struct drm_intel_sprite_colorkey *key) +{ + struct drm_device *dev = dplane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane *intel_plane = to_intel_plane(dplane); + int pipe = intel_plane->pipe; + int plane = intel_plane->plane; + u32 sprctl; + + key->min_value = I915_READ(SPKEYMINVAL(pipe, plane)); + key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane)); + key->channel_mask = I915_READ(SPKEYMSK(pipe, plane)); + + sprctl = I915_READ(SPCNTR(pipe, plane)); + if (sprctl & SP_SOURCE_KEY) + key->flags = I915_SET_COLORKEY_SOURCE; + else + key->flags = I915_SET_COLORKEY_NONE; +} + +static void ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, @@ -441,6 +609,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, old_obj = intel_plane->obj; + intel_plane->crtc_x = crtc_x; + intel_plane->crtc_y = crtc_y; + intel_plane->crtc_w = crtc_w; + intel_plane->crtc_h = crtc_h; + intel_plane->src_x = src_x; + intel_plane->src_y = src_y; + intel_plane->src_w = src_w; + intel_plane->src_h = src_h; + src_w = src_w >> 16; src_h = src_h >> 16; @@ -513,6 +690,11 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, mutex_lock(&dev->struct_mutex); + /* Note that this will apply the VT-d workaround for scanouts, + * which is more restrictive than required for sprites. (The + * primary plane requires 256KiB alignment with 64 PTE padding, + * the sprite planes only require 128KiB alignment and 32 PTE padding. + */ ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) goto out_unlock; @@ -568,6 +750,8 @@ intel_disable_plane(struct drm_plane *plane) if (!intel_plane->obj) goto out; + intel_wait_for_vblank(dev, intel_plane->pipe); + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(intel_plane->obj); intel_plane->obj = NULL; @@ -647,6 +831,20 @@ out_unlock: return ret; } +void intel_plane_restore(struct drm_plane *plane) +{ + struct intel_plane *intel_plane = to_intel_plane(plane); + + if (!plane->crtc || !plane->fb) + return; + + intel_update_plane(plane, plane->crtc, plane->fb, + intel_plane->crtc_x, intel_plane->crtc_y, + intel_plane->crtc_w, intel_plane->crtc_h, + intel_plane->src_x, intel_plane->src_y, + intel_plane->src_w, intel_plane->src_h); +} + static const struct drm_plane_funcs intel_plane_funcs = { .update_plane = intel_update_plane, .disable_plane = intel_disable_plane, @@ -670,8 +868,22 @@ static uint32_t snb_plane_formats[] = { DRM_FORMAT_VYUY, }; +static uint32_t vlv_plane_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, +}; + int -intel_plane_init(struct drm_device *dev, enum pipe pipe) +intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) { struct intel_plane *intel_plane; unsigned long possible_crtcs; @@ -710,14 +922,26 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) intel_plane->can_scale = false; else intel_plane->can_scale = true; - intel_plane->max_downscale = 2; - intel_plane->update_plane = ivb_update_plane; - intel_plane->disable_plane = ivb_disable_plane; - intel_plane->update_colorkey = ivb_update_colorkey; - intel_plane->get_colorkey = ivb_get_colorkey; - - plane_formats = snb_plane_formats; - num_plane_formats = ARRAY_SIZE(snb_plane_formats); + + if (IS_VALLEYVIEW(dev)) { + intel_plane->max_downscale = 1; + intel_plane->update_plane = vlv_update_plane; + intel_plane->disable_plane = vlv_disable_plane; + intel_plane->update_colorkey = vlv_update_colorkey; + intel_plane->get_colorkey = vlv_get_colorkey; + + plane_formats = vlv_plane_formats; + num_plane_formats = ARRAY_SIZE(vlv_plane_formats); + } else { + intel_plane->max_downscale = 2; + intel_plane->update_plane = ivb_update_plane; + intel_plane->disable_plane = ivb_disable_plane; + intel_plane->update_colorkey = ivb_update_colorkey; + intel_plane->get_colorkey = ivb_get_colorkey; + + plane_formats = snb_plane_formats; + num_plane_formats = ARRAY_SIZE(snb_plane_formats); + } break; default: @@ -726,6 +950,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) } intel_plane->pipe = pipe; + intel_plane->plane = plane; possible_crtcs = (1 << pipe); ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index d808421..b945bc5 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -905,11 +905,10 @@ intel_tv_mode_valid(struct drm_connector *connector, static bool -intel_tv_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +intel_tv_compute_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { - struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(&encoder->base); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); if (!tv_mode) @@ -918,7 +917,10 @@ intel_tv_mode_fixup(struct drm_encoder *encoder, if (intel_encoder_check_is_cloned(&intel_tv->base)) return false; - adjusted_mode->clock = tv_mode->clock; + pipe_config->adjusted_mode.clock = tv_mode->clock; + DRM_DEBUG_KMS("forcing bpc to 8 for TV\n"); + pipe_config->pipe_bpp = 8*3; + return true; } @@ -1485,7 +1487,6 @@ out: } static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { - .mode_fixup = intel_tv_mode_fixup, .mode_set = intel_tv_mode_set, }; @@ -1612,7 +1613,7 @@ intel_tv_init(struct drm_device *dev) * * More recent chipsets favour HDMI rather than integrated S-Video. */ - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); @@ -1620,6 +1621,7 @@ intel_tv_init(struct drm_device *dev) drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); + intel_encoder->compute_config = intel_tv_compute_config; intel_encoder->enable = intel_enable_tv; intel_encoder->disable = intel_disable_tv; intel_encoder->get_hw_state = intel_tv_get_hw_state; |