diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
31 files changed, 5660 insertions, 2808 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index dde8b50..e6a11ca8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -317,7 +317,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) seq_printf(m, "No flip due on pipe %c (plane %c)\n", pipe, plane); } else { - if (!work->pending) { + if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { seq_printf(m, "Flip queued on pipe %c (plane %c)\n", pipe, plane); } else { @@ -328,7 +328,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) seq_printf(m, "Stall check enabled, "); else seq_printf(m, "Stall check waiting for page flip ioctl, "); - seq_printf(m, "%d prepares\n", work->pending); + seq_printf(m, "%d prepares\n", atomic_read(&work->pending)); if (work->old_fb_obj) { struct drm_i915_gem_object *obj = work->old_fb_obj; @@ -655,10 +655,12 @@ static void i915_ring_error_state(struct seq_file *m, if (INTEL_INFO(dev)->gen >= 6) { seq_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]); seq_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); - seq_printf(m, " SYNC_0: 0x%08x\n", - error->semaphore_mboxes[ring][0]); - seq_printf(m, " SYNC_1: 0x%08x\n", - error->semaphore_mboxes[ring][1]); + seq_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n", + error->semaphore_mboxes[ring][0], + error->semaphore_seqno[ring][0]); + seq_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n", + error->semaphore_mboxes[ring][1], + error->semaphore_seqno[ring][1]); } seq_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); seq_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); @@ -1068,7 +1070,7 @@ static int gen6_drpc_info(struct seq_file *m) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 rpmodectl1, gt_core_status, rcctl1; + u32 rpmodectl1, gt_core_status, rcctl1, rc6vids = 0; unsigned forcewake_count; int count=0, ret; @@ -1097,6 +1099,9 @@ static int gen6_drpc_info(struct seq_file *m) rpmodectl1 = I915_READ(GEN6_RP_CONTROL); rcctl1 = I915_READ(GEN6_RC_CONTROL); mutex_unlock(&dev->struct_mutex); + mutex_lock(&dev_priv->rps.hw_lock); + sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); + mutex_unlock(&dev_priv->rps.hw_lock); seq_printf(m, "Video Turbo Mode: %s\n", yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); @@ -1148,6 +1153,12 @@ static int gen6_drpc_info(struct seq_file *m) seq_printf(m, "RC6++ residency since boot: %u\n", I915_READ(GEN6_GT_GFX_RC6pp)); + seq_printf(m, "RC6 voltage: %dmV\n", + GEN6_DECODE_RC6_VID(((rc6vids >> 0) & 0xff))); + seq_printf(m, "RC6+ voltage: %dmV\n", + GEN6_DECODE_RC6_VID(((rc6vids >> 8) & 0xff))); + seq_printf(m, "RC6++ voltage: %dmV\n", + GEN6_DECODE_RC6_VID(((rc6vids >> 16) & 0xff))); return 0; } @@ -1273,7 +1284,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) return 0; } - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1282,19 +1293,14 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) for (gpu_freq = dev_priv->rps.min_delay; gpu_freq <= dev_priv->rps.max_delay; gpu_freq++) { - I915_WRITE(GEN6_PCODE_DATA, gpu_freq); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | - GEN6_PCODE_READ_MIN_FREQ_TABLE); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & - GEN6_PCODE_READY) == 0, 10)) { - DRM_ERROR("pcode read of freq table timed out\n"); - continue; - } - ia_freq = I915_READ(GEN6_PCODE_DATA); + ia_freq = gpu_freq; + 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); } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return 0; } @@ -1398,15 +1404,15 @@ static int i915_context_status(struct seq_file *m, void *unused) if (ret) return ret; - if (dev_priv->pwrctx) { + if (dev_priv->ips.pwrctx) { seq_printf(m, "power context "); - describe_obj(m, dev_priv->pwrctx); + describe_obj(m, dev_priv->ips.pwrctx); seq_printf(m, "\n"); } - if (dev_priv->renderctx) { + if (dev_priv->ips.renderctx) { seq_printf(m, "render context "); - describe_obj(m, dev_priv->renderctx); + describe_obj(m, dev_priv->ips.renderctx); seq_printf(m, "\n"); } @@ -1711,13 +1717,13 @@ i915_max_freq_read(struct file *filp, if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; len = snprintf(buf, sizeof(buf), "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); if (len > sizeof(buf)) len = sizeof(buf); @@ -1752,7 +1758,7 @@ i915_max_freq_write(struct file *filp, DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val); - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1762,7 +1768,7 @@ i915_max_freq_write(struct file *filp, dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER; gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return cnt; } @@ -1787,13 +1793,13 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, if (!(IS_GEN6(dev) || IS_GEN7(dev))) return -ENODEV; - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; len = snprintf(buf, sizeof(buf), "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); if (len > sizeof(buf)) len = sizeof(buf); @@ -1826,7 +1832,7 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val); - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; @@ -1836,7 +1842,7 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER; gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return cnt; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 61ae104..8f63cd5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -104,32 +104,6 @@ static void i915_write_hws_pga(struct drm_device *dev) } /** - * Sets up the hardware status page for devices that need a physical address - * in the register. - */ -static int i915_init_phys_hws(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - /* Program Hardware Status Page */ - dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE); - - if (!dev_priv->status_page_dmah) { - DRM_ERROR("Can not allocate hardware status page\n"); - return -ENOMEM; - } - - memset_io((void __force __iomem *)dev_priv->status_page_dmah->vaddr, - 0, PAGE_SIZE); - - i915_write_hws_pga(dev); - - DRM_DEBUG_DRIVER("Enabled hardware status page\n"); - return 0; -} - -/** * Frees the hardware status page, whether it's a physical address or a virtual * address set up by the X Server. */ @@ -167,7 +141,7 @@ void i915_kernel_lost_context(struct drm_device * dev) ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); + ring->space = ring->head - (ring->tail + I915_RING_FREE_SPACE); if (ring->space < 0) ring->space += ring->size; @@ -451,16 +425,16 @@ static void i915_emit_breadcrumb(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - dev_priv->counter++; - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->counter = 0; + dev_priv->dri1.counter++; + if (dev_priv->dri1.counter > 0x7FFFFFFFUL) + dev_priv->dri1.counter = 0; if (master_priv->sarea_priv) - master_priv->sarea_priv->last_enqueue = dev_priv->counter; + master_priv->sarea_priv->last_enqueue = dev_priv->dri1.counter; if (BEGIN_LP_RING(4) == 0) { OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); + OUT_RING(dev_priv->dri1.counter); OUT_RING(0); ADVANCE_LP_RING(); } @@ -602,12 +576,12 @@ static int i915_dispatch_flip(struct drm_device * dev) ADVANCE_LP_RING(); - master_priv->sarea_priv->last_enqueue = dev_priv->counter++; + master_priv->sarea_priv->last_enqueue = dev_priv->dri1.counter++; if (BEGIN_LP_RING(4) == 0) { OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); + OUT_RING(dev_priv->dri1.counter); OUT_RING(0); ADVANCE_LP_RING(); } @@ -618,10 +592,8 @@ static int i915_dispatch_flip(struct drm_device * dev) static int i915_quiescent(struct drm_device *dev) { - struct intel_ring_buffer *ring = LP_RING(dev->dev_private); - i915_kernel_lost_context(dev); - return intel_wait_ring_idle(ring); + return intel_ring_idle(LP_RING(dev->dev_private)); } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -775,21 +747,21 @@ static int i915_emit_irq(struct drm_device * dev) DRM_DEBUG_DRIVER("\n"); - dev_priv->counter++; - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->counter = 1; + dev_priv->dri1.counter++; + if (dev_priv->dri1.counter > 0x7FFFFFFFUL) + dev_priv->dri1.counter = 1; if (master_priv->sarea_priv) - master_priv->sarea_priv->last_enqueue = dev_priv->counter; + master_priv->sarea_priv->last_enqueue = dev_priv->dri1.counter; if (BEGIN_LP_RING(4) == 0) { OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); + OUT_RING(dev_priv->dri1.counter); OUT_RING(MI_USER_INTERRUPT); ADVANCE_LP_RING(); } - return dev_priv->counter; + return dev_priv->dri1.counter; } static int i915_wait_irq(struct drm_device * dev, int irq_nr) @@ -820,7 +792,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", - READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); + READ_BREADCRUMB(dev_priv), (int)dev_priv->dri1.counter); } return ret; @@ -1014,6 +986,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_PRIME_VMAP_FLUSH: value = 1; break; + case I915_PARAM_HAS_SECURE_BATCHES: + value = capable(CAP_SYS_ADMIN); + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); @@ -1068,7 +1043,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_hws_addr_t *hws = data; - struct intel_ring_buffer *ring = LP_RING(dev_priv); + struct intel_ring_buffer *ring; if (drm_core_check_feature(dev, DRIVER_MODESET)) return -ENODEV; @@ -1088,6 +1063,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr); + ring = LP_RING(dev_priv); ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); dev_priv->dri1.gfx_hws_cpu_addr = @@ -1326,6 +1302,8 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_modeset_gem_init(dev); + INIT_WORK(&dev_priv->console_resume_work, intel_console_resume); + ret = drm_irq_install(dev); if (ret) goto cleanup_gem; @@ -1491,19 +1469,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto free_priv; } - ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL); - if (!ret) { - DRM_ERROR("failed to set up gmch\n"); - ret = -EIO; + ret = i915_gem_gtt_init(dev); + if (ret) goto put_bridge; - } - - dev_priv->mm.gtt = intel_gtt_get(); - if (!dev_priv->mm.gtt) { - DRM_ERROR("Failed to initialize GTT\n"); - ret = -ENODEV; - goto put_gmch; - } if (drm_core_check_feature(dev, DRIVER_MODESET)) i915_kick_out_firmware_fb(dev_priv); @@ -1590,18 +1558,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_setup_gmbus(dev); intel_opregion_setup(dev); - /* Make sure the bios did its job and set up vital registers */ intel_setup_bios(dev); i915_gem_load(dev); - /* Init HWS */ - if (!I915_NEED_GFX_HWS(dev)) { - ret = i915_init_phys_hws(dev); - if (ret) - goto out_gem_unload; - } - /* On the 945G/GM, the chipset reports the MSI capability on the * integrated graphics even though the support isn't actually there * according to the published specs. It doesn't appear to function @@ -1621,6 +1581,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->rps.lock); spin_lock_init(&dev_priv->dpio_lock); + mutex_init(&dev_priv->rps.hw_lock); + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; else if (IS_MOBILE(dev) || !IS_GEN2(dev)) @@ -1678,7 +1640,7 @@ out_mtrrfree: out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); put_gmch: - intel_gmch_remove(); + i915_gem_gtt_fini(dev); put_bridge: pci_dev_put(dev_priv->bridge_dev); free_priv: @@ -1721,6 +1683,7 @@ int i915_driver_unload(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_fbdev_fini(dev); intel_modeset_cleanup(dev); + cancel_work_sync(&dev_priv->console_resume_work); /* * free the memory space allocated for the child device diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 6770ee6..530db83 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -47,11 +47,11 @@ MODULE_PARM_DESC(modeset, unsigned int i915_fbpercrtc __always_unused = 0; module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); -int i915_panel_ignore_lid __read_mostly = 0; +int i915_panel_ignore_lid __read_mostly = 1; module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); MODULE_PARM_DESC(panel_ignore_lid, - "Override lid status (0=autodetect [default], 1=lid open, " - "-1=lid closed)"); + "Override lid status (0=autodetect, 1=autodetect disabled [default], " + "-1=force lid closed, -2=force lid open)"); unsigned int i915_powersave __read_mostly = 1; module_param_named(powersave, i915_powersave, int, 0600); @@ -396,12 +396,6 @@ static const struct pci_device_id pciidlist[] = { /* aka */ MODULE_DEVICE_TABLE(pci, pciidlist); #endif -#define INTEL_PCH_DEVICE_ID_MASK 0xff00 -#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 -#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 -#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 -#define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00 - void intel_detect_pch(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -416,26 +410,36 @@ void intel_detect_pch(struct drm_device *dev) pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); if (pch) { if (pch->vendor == PCI_VENDOR_ID_INTEL) { - int id; + unsigned short id; id = pch->device & INTEL_PCH_DEVICE_ID_MASK; + dev_priv->pch_id = id; if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_IBX; dev_priv->num_pch_pll = 2; DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); + WARN_ON(!IS_GEN5(dev)); } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_CPT; dev_priv->num_pch_pll = 2; DRM_DEBUG_KMS("Found CougarPoint PCH\n"); + WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev))); } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { /* PantherPoint is CPT compatible */ dev_priv->pch_type = PCH_CPT; dev_priv->num_pch_pll = 2; DRM_DEBUG_KMS("Found PatherPoint PCH\n"); + WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev))); } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; dev_priv->num_pch_pll = 0; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); + WARN_ON(!IS_HASWELL(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)); } BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); } @@ -477,6 +481,8 @@ static int i915_drm_freeze(struct drm_device *dev) return error; } + cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); + intel_modeset_disable(dev); drm_irq_uninstall(dev); @@ -526,24 +532,29 @@ int i915_suspend(struct drm_device *dev, pm_message_t state) return 0; } -static int i915_drm_thaw(struct drm_device *dev) +void intel_console_resume(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, + console_resume_work); + struct drm_device *dev = dev_priv->dev; + + console_lock(); + intel_fbdev_set_suspend(dev, 0); + console_unlock(); +} + +static int __i915_drm_thaw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int error = 0; - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - mutex_lock(&dev->struct_mutex); - i915_gem_restore_gtt_mappings(dev); - mutex_unlock(&dev->struct_mutex); - } - i915_restore_state(dev); intel_opregion_setup(dev); /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) - ironlake_init_pch_refclk(dev); + intel_init_pch_refclk(dev); mutex_lock(&dev->struct_mutex); dev_priv->mm.suspended = 0; @@ -552,8 +563,7 @@ static int i915_drm_thaw(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); intel_modeset_init_hw(dev); - intel_modeset_setup_hw_state(dev); - drm_mode_config_reset(dev); + intel_modeset_setup_hw_state(dev, false); drm_irq_install(dev); } @@ -561,14 +571,41 @@ static int i915_drm_thaw(struct drm_device *dev) dev_priv->modeset_on_lid = 0; - console_lock(); - intel_fbdev_set_suspend(dev, 0); - console_unlock(); + /* + * The console lock can be pretty contented on resume due + * to all the printk activity. Try to keep it out of the hot + * path of resume if possible. + */ + if (console_trylock()) { + intel_fbdev_set_suspend(dev, 0); + console_unlock(); + } else { + schedule_work(&dev_priv->console_resume_work); + } + + return error; +} + +static int i915_drm_thaw(struct drm_device *dev) +{ + int error = 0; + + intel_gt_reset(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + mutex_lock(&dev->struct_mutex); + i915_gem_restore_gtt_mappings(dev); + mutex_unlock(&dev->struct_mutex); + } + + __i915_drm_thaw(dev); + return error; } int i915_resume(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; int ret; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -579,7 +616,20 @@ int i915_resume(struct drm_device *dev) pci_set_master(dev->pdev); - ret = i915_drm_thaw(dev); + intel_gt_reset(dev); + + /* + * Platforms with opregion should have sane BIOS, older ones (gen3 and + * earlier) need this since the BIOS might clear all our scratch PTEs. + */ + if (drm_core_check_feature(dev, DRIVER_MODESET) && + !dev_priv->opregion.header) { + mutex_lock(&dev->struct_mutex); + i915_gem_restore_gtt_mappings(dev); + mutex_unlock(&dev->struct_mutex); + } + + ret = __i915_drm_thaw(dev); if (ret) return ret; @@ -833,7 +883,7 @@ i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct intel_device_info *intel_info = (struct intel_device_info *) ent->driver_data; - if (intel_info->is_haswell || intel_info->is_valleyview) + if (intel_info->is_valleyview) if(!i915_preliminary_hw_support) { DRM_ERROR("Preliminary hardware support disabled\n"); return -ENODEV; @@ -1140,12 +1190,40 @@ static bool IS_DISPLAYREG(u32 reg) if (reg == GEN6_GDRST) return false; + switch (reg) { + case _3D_CHICKEN3: + case IVB_CHICKEN3: + case GEN7_COMMON_SLICE_CHICKEN1: + case GEN7_L3CNTLREG1: + case GEN7_L3_CHICKEN_MODE_REGISTER: + case GEN7_ROW_CHICKEN2: + case GEN7_L3SQCREG4: + case GEN7_SQ_CHICKEN_MBCUNIT_CONFIG: + case GEN7_HALF_SLICE_CHICKEN1: + case GEN6_MBCTL: + case GEN6_UCGCTL2: + return false; + default: + break; + } + return true; } +static void +ilk_dummy_write(struct drm_i915_private *dev_priv) +{ + /* WaIssueDummyWriteToWakeupFromRC6: Issue a dummy write to wake up the + * chip from rc6 before touching it for real. MI_MODE is masked, hence + * harmless to write 0 into. */ + I915_WRITE_NOTRACE(MI_MODE, 0); +} + #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ + if (IS_GEN5(dev_priv->dev)) \ + ilk_dummy_write(dev_priv); \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ unsigned long irqflags; \ spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ @@ -1177,6 +1255,12 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + 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); \ + } \ if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ write##y(val, dev_priv->regs + reg + 0x180000); \ } else { \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f511fa2..557843d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -58,6 +58,14 @@ enum pipe { }; #define pipe_name(p) ((p) + 'A') +enum transcoder { + TRANSCODER_A = 0, + TRANSCODER_B, + TRANSCODER_C, + TRANSCODER_EDP = 0xF, +}; +#define transcoder_name(t) ((t) + 'A') + enum plane { PLANE_A = 0, PLANE_B, @@ -93,6 +101,12 @@ struct intel_pch_pll { }; #define I915_NUM_PLLS 2 +struct intel_ddi_plls { + int spll_refcount; + int wrpll1_refcount; + int wrpll2_refcount; +}; + /* Interface history: * * 1.1: Original. @@ -123,14 +137,6 @@ struct drm_i915_gem_phys_object { struct drm_i915_gem_object *cur_obj; }; -struct mem_block { - struct mem_block *next; - struct mem_block *prev; - int start; - int size; - struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ -}; - struct opregion_header; struct opregion_acpi; struct opregion_swsci; @@ -191,6 +197,7 @@ struct drm_i915_error_state { u32 instdone[I915_NUM_RINGS]; u32 acthd[I915_NUM_RINGS]; u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1]; + u32 semaphore_seqno[I915_NUM_RINGS][I915_NUM_RINGS - 1]; u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */ /* our own tracking of ring head and tail */ u32 cpu_ring_head[I915_NUM_RINGS]; @@ -251,6 +258,7 @@ struct drm_i915_display_funcs { uint32_t sprite_width, int pixel_size); void (*update_linetime_wm)(struct drm_device *dev, int pipe, struct drm_display_mode *mode); + void (*modeset_global_resources)(struct drm_device *dev); int (*crtc_mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -263,7 +271,6 @@ struct drm_i915_display_funcs { struct drm_crtc *crtc); void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); - void (*init_pch_clock_gating)(struct drm_device *dev); int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj); @@ -338,6 +345,7 @@ struct intel_device_info { #define I915_PPGTT_PD_ENTRIES 512 #define I915_PPGTT_PT_ENTRIES 1024 struct i915_hw_ppgtt { + struct drm_device *dev; unsigned num_pd_entries; struct page **pt_pages; uint32_t pd_offset; @@ -374,6 +382,11 @@ enum intel_pch { PCH_LPT, /* Lynxpoint PCH */ }; +enum intel_sbi_destination { + SBI_ICLK, + SBI_MPHY, +}; + #define QUIRK_PIPEA_FORCE (1<<0) #define QUIRK_LVDS_SSC_DISABLE (1<<1) #define QUIRK_INVERT_BRIGHTNESS (1<<2) @@ -383,154 +396,18 @@ struct intel_fbc_work; struct intel_gmbus { struct i2c_adapter adapter; - bool force_bit; + u32 force_bit; u32 reg0; u32 gpio_reg; struct i2c_algo_bit_data bit_algo; struct drm_i915_private *dev_priv; }; -typedef struct drm_i915_private { - struct drm_device *dev; - - const struct intel_device_info *info; - - int relative_constants_mode; - - void __iomem *regs; - - struct drm_i915_gt_funcs gt; - /** gt_fifo_count and the subsequent register write are synchronized - * with dev->struct_mutex. */ - unsigned gt_fifo_count; - /** forcewake_count is protected by gt_lock */ - unsigned forcewake_count; - /** gt_lock is also taken in irq contexts. */ - struct spinlock gt_lock; - - struct intel_gmbus gmbus[GMBUS_NUM_PORTS]; - - /** gmbus_mutex protects against concurrent usage of the single hw gmbus - * controller on different i2c buses. */ - struct mutex gmbus_mutex; - - /** - * Base address of the gmbus and gpio block. - */ - uint32_t gpio_mmio_base; - - struct pci_dev *bridge_dev; - struct intel_ring_buffer ring[I915_NUM_RINGS]; - uint32_t next_seqno; - - drm_dma_handle_t *status_page_dmah; - uint32_t counter; - struct drm_i915_gem_object *pwrctx; - struct drm_i915_gem_object *renderctx; - - struct resource mch_res; - - atomic_t irq_received; - - /* protects the irq masks */ - spinlock_t irq_lock; - - /* DPIO indirect register protection */ - spinlock_t dpio_lock; - - /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 pipestat[2]; - u32 irq_mask; - u32 gt_irq_mask; - u32 pch_irq_mask; - - u32 hotplug_supported_mask; - struct work_struct hotplug_work; - - int num_pipe; - int num_pch_pll; - - /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ - struct timer_list hangcheck_timer; - int hangcheck_count; - uint32_t last_acthd[I915_NUM_RINGS]; - uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; - - unsigned int stop_rings; - - unsigned long cfb_size; - unsigned int cfb_fb; - enum plane cfb_plane; - int cfb_y; - struct intel_fbc_work *fbc_work; - - struct intel_opregion opregion; - - /* overlay */ - struct intel_overlay *overlay; - bool sprite_scaling_enabled; - - /* 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 */ - - /* Feature bits from the VBIOS */ - unsigned int int_tv_support:1; - unsigned int lvds_dither:1; - unsigned int lvds_vbt:1; - unsigned int int_crt_support:1; - unsigned int lvds_use_ssc:1; - unsigned int display_clock_mode:1; - int lvds_ssc_freq; - unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ - unsigned int lvds_val; /* used for checking LVDS channel mode */ - struct { - int rate; - int lanes; - int preemphasis; - int vswing; - - bool initialized; - bool support; - int bpp; - struct edp_power_seq pps; - } edp; - bool no_aux_handshake; - - struct notifier_block lid_notifier; - - int crt_ddc_pin; - struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ - int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ - int num_fence_regs; /* 8 on pre-965, 16 otherwise */ - - unsigned int fsb_freq, mem_freq, is_ddr3; - - spinlock_t error_lock; - /* Protected by dev->error_lock. */ - struct drm_i915_error_state *first_error; - struct work_struct error_work; - struct completion error_completion; - struct workqueue_struct *wq; - - /* Display functions */ - struct drm_i915_display_funcs display; - - /* PCH chipset type */ - enum intel_pch pch_type; - - unsigned long quirks; - - /* Register state */ - bool modeset_on_lid; +struct i915_suspend_saved_registers { u8 saveLBB; u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; - u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; @@ -676,10 +553,206 @@ typedef struct drm_i915_private { u32 savePIPEB_LINK_N1; u32 saveMCHBAR_RENDER_STANDBY; u32 savePCH_PORT_HOTPLUG; +}; + +struct intel_gen6_power_mgmt { + struct work_struct work; + u32 pm_iir; + /* lock - irqsave spinlock that protectects the work_struct and + * pm_iir. */ + spinlock_t lock; + + /* The below variables an all the rps hw state are protected by + * dev->struct mutext. */ + u8 cur_delay; + u8 min_delay; + u8 max_delay; + + struct delayed_work delayed_resume_work; + + /* + * Protects RPS/RC6 register access and PCU communication. + * Must be taken after struct_mutex if nested. + */ + struct mutex hw_lock; +}; + +struct intel_ilk_power_mgmt { + u8 cur_delay; + u8 min_delay; + u8 max_delay; + u8 fmax; + u8 fstart; + + u64 last_count1; + unsigned long last_time1; + unsigned long chipset_power; + u64 last_count2; + struct timespec last_time2; + unsigned long gfx_power; + u8 corr; + + int c_m; + int r_t; + + struct drm_i915_gem_object *pwrctx; + struct drm_i915_gem_object *renderctx; +}; + +struct i915_dri1_state { + unsigned allow_batchbuffer : 1; + u32 __iomem *gfx_hws_cpu_addr; + + unsigned int cpp; + int back_offset; + int front_offset; + int current_page; + int page_flipping; + + uint32_t counter; +}; + +struct intel_l3_parity { + u32 *remap_info; + struct work_struct error_work; +}; + +typedef struct drm_i915_private { + struct drm_device *dev; + + const struct intel_device_info *info; + + int relative_constants_mode; + + void __iomem *regs; + + struct drm_i915_gt_funcs gt; + /** gt_fifo_count and the subsequent register write are synchronized + * with dev->struct_mutex. */ + unsigned gt_fifo_count; + /** forcewake_count is protected by gt_lock */ + unsigned forcewake_count; + /** gt_lock is also taken in irq contexts. */ + struct spinlock gt_lock; + + struct intel_gmbus gmbus[GMBUS_NUM_PORTS]; + + /** gmbus_mutex protects against concurrent usage of the single hw gmbus + * controller on different i2c buses. */ + struct mutex gmbus_mutex; + + /** + * Base address of the gmbus and gpio block. + */ + uint32_t gpio_mmio_base; + + struct pci_dev *bridge_dev; + struct intel_ring_buffer ring[I915_NUM_RINGS]; + uint32_t next_seqno; + + drm_dma_handle_t *status_page_dmah; + struct resource mch_res; + + atomic_t irq_received; + + /* protects the irq masks */ + spinlock_t irq_lock; + + /* DPIO indirect register protection */ + spinlock_t dpio_lock; + + /** Cached value of IMR to avoid reads in updating the bitfield */ + u32 pipestat[2]; + u32 irq_mask; + u32 gt_irq_mask; + u32 pch_irq_mask; + + u32 hotplug_supported_mask; + struct work_struct hotplug_work; + + int num_pipe; + int num_pch_pll; + + /* For hangcheck timer */ +#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ +#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) + struct timer_list hangcheck_timer; + int hangcheck_count; + uint32_t last_acthd[I915_NUM_RINGS]; + uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; + + unsigned int stop_rings; + + unsigned long cfb_size; + unsigned int cfb_fb; + enum plane cfb_plane; + int cfb_y; + struct intel_fbc_work *fbc_work; + + struct intel_opregion opregion; + + /* overlay */ + struct intel_overlay *overlay; + bool sprite_scaling_enabled; + + /* 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 */ + + /* Feature bits from the VBIOS */ + unsigned int int_tv_support:1; + unsigned int lvds_dither:1; + unsigned int lvds_vbt:1; + unsigned int int_crt_support:1; + unsigned int lvds_use_ssc:1; + unsigned int display_clock_mode:1; + int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + unsigned int lvds_val; /* used for checking LVDS channel mode */ + struct { + int rate; + int lanes; + int preemphasis; + int vswing; + + bool initialized; + bool support; + int bpp; + struct edp_power_seq pps; + } edp; + bool no_aux_handshake; + + int crt_ddc_pin; + struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ + int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ + int num_fence_regs; /* 8 on pre-965, 16 otherwise */ + + unsigned int fsb_freq, mem_freq, is_ddr3; + + spinlock_t error_lock; + /* Protected by dev->error_lock. */ + struct drm_i915_error_state *first_error; + struct work_struct error_work; + struct completion error_completion; + struct workqueue_struct *wq; + + /* Display functions */ + struct drm_i915_display_funcs display; + + /* PCH chipset type */ + enum intel_pch pch_type; + unsigned short pch_id; + + unsigned long quirks; + + /* Register state */ + bool modeset_on_lid; struct { /** Bridge to intel-gtt-ko */ - const struct intel_gtt *gtt; + struct intel_gtt *gtt; /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; /** Memory allocator for GTT */ @@ -706,8 +779,6 @@ typedef struct drm_i915_private { /** PPGTT used for aliasing the PPGTT with the GTT */ struct i915_hw_ppgtt *aliasing_ppgtt; - u32 *l3_remap_info; - struct shrinker inactive_shrinker; /** @@ -785,19 +856,6 @@ typedef struct drm_i915_private { u32 object_count; } mm; - /* Old dri1 support infrastructure, beware the dragons ya fools entering - * here! */ - struct { - unsigned allow_batchbuffer : 1; - u32 __iomem *gfx_hws_cpu_addr; - - unsigned int cpp; - int back_offset; - int front_offset; - int current_page; - int page_flipping; - } dri1; - /* Kernel Modesetting */ struct sdvo_device_mapping sdvo_mappings[2]; @@ -811,6 +869,7 @@ typedef struct drm_i915_private { wait_queue_head_t pending_flip_queue; struct intel_pch_pll pch_plls[I915_NUM_PLLS]; + struct intel_ddi_plls ddi_plls; /* Reclocking support */ bool render_reclock_avail; @@ -820,46 +879,17 @@ typedef struct drm_i915_private { u16 orig_clock; int child_dev_num; struct child_device_config *child_dev; - struct drm_connector *int_lvds_connector; - struct drm_connector *int_edp_connector; bool mchbar_need_disable; + struct intel_l3_parity l3_parity; + /* gen6+ rps state */ - struct { - struct work_struct work; - u32 pm_iir; - /* lock - irqsave spinlock that protectects the work_struct and - * pm_iir. */ - spinlock_t lock; - - /* The below variables an all the rps hw state are protected by - * dev->struct mutext. */ - u8 cur_delay; - u8 min_delay; - u8 max_delay; - } rps; + struct intel_gen6_power_mgmt rps; /* ilk-only ips/rps state. Everything in here is protected by the global * mchdev_lock in intel_pm.c */ - struct { - u8 cur_delay; - u8 min_delay; - u8 max_delay; - u8 fmax; - u8 fstart; - - u64 last_count1; - unsigned long last_time1; - unsigned long chipset_power; - u64 last_count2; - struct timespec last_time2; - unsigned long gfx_power; - u8 corr; - - int c_m; - int r_t; - } ips; + struct intel_ilk_power_mgmt ips; enum no_fbc_reason no_fbc_reason; @@ -871,14 +901,27 @@ typedef struct drm_i915_private { /* list of fbdev register on this device */ struct intel_fbdev *fbdev; + /* + * The console may be contended at resume, but we don't + * want it to block on it. + */ + struct work_struct console_resume_work; + struct backlight_device *backlight; struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; - struct work_struct parity_error_work; bool hw_contexts_disabled; uint32_t hw_context_size; + + bool fdi_rx_polarity_reversed; + + struct i915_suspend_saved_registers regfile; + + /* Old dri1 support infrastructure, beware the dragons ya fools entering + * here! */ + struct i915_dri1_state dri1; } drm_i915_private_t; /* Iterate over initialised rings */ @@ -1120,9 +1163,14 @@ struct drm_i915_file_private { #define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) #define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge) +#define IS_IVB_GT1(dev) ((dev)->pci_device == 0x0156 || \ + (dev)->pci_device == 0x0152 || \ + (dev)->pci_device == 0x015a) #define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview) #define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) +#define IS_ULT(dev) (IS_HASWELL(dev) && \ + ((dev)->pci_device & 0xFF00) == 0x0A00) /* * The genX designation typically refers to the render engine, so render @@ -1168,6 +1216,13 @@ struct drm_i915_file_private { #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) +#define INTEL_PCH_DEVICE_ID_MASK 0xff00 +#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 +#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 +#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 +#define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00 +#define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00 + #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) @@ -1250,6 +1305,7 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); +extern void intel_console_resume(struct work_struct *work); /* i915_irq.c */ void i915_hangcheck_elapsed(unsigned long data); @@ -1257,6 +1313,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged); extern void intel_irq_init(struct drm_device *dev); extern void intel_gt_init(struct drm_device *dev); +extern void intel_gt_reset(struct drm_device *dev); void i915_error_state_free(struct kref *error_ref); @@ -1368,8 +1425,7 @@ int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_ring_buffer *to); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring, - u32 seqno); + struct intel_ring_buffer *ring); int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, @@ -1387,7 +1443,7 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } -u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring); +extern int i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); @@ -1499,6 +1555,14 @@ void i915_gem_init_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end); +int i915_gem_gtt_init(struct drm_device *dev); +void i915_gem_gtt_fini(struct drm_device *dev); +static inline void i915_gem_chipset_flush(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen < 6) + intel_gtt_chipset_flush(); +} + /* i915_gem_evict.c */ int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size, @@ -1595,11 +1659,12 @@ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); -extern void intel_modeset_setup_hw_state(struct drm_device *dev); +extern void intel_modeset_setup_hw_state(struct drm_device *dev, + bool force_restore); extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); -extern void ironlake_init_pch_refclk(struct drm_device *dev); +extern void intel_init_pch_refclk(struct drm_device *dev); extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); @@ -1628,6 +1693,9 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); 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); + #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9b285da..742206e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -845,12 +845,12 @@ out: * domain anymore. */ if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) { i915_gem_clflush_object(obj); - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(dev); } } if (needs_clflush_after) - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(dev); return ret; } @@ -1345,30 +1345,17 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) trace_i915_gem_object_fault(obj, page_offset, true, write); /* Now bind it into the GTT if needed */ - if (!obj->map_and_fenceable) { - ret = i915_gem_object_unbind(obj); - if (ret) - goto unlock; - } - if (!obj->gtt_space) { - ret = i915_gem_object_bind_to_gtt(obj, 0, true, false); - if (ret) - goto unlock; - - ret = i915_gem_object_set_to_gtt_domain(obj, write); - if (ret) - goto unlock; - } + ret = i915_gem_object_pin(obj, 0, true, false); + if (ret) + goto unlock; - if (!obj->has_global_gtt_mapping) - i915_gem_gtt_bind_object(obj, obj->cache_level); + ret = i915_gem_object_set_to_gtt_domain(obj, write); + if (ret) + goto unpin; ret = i915_gem_object_get_fence(obj); if (ret) - goto unlock; - - if (i915_gem_object_is_inactive(obj)) - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + goto unpin; obj->fault_mappable = true; @@ -1377,6 +1364,8 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Finally, remap it using the new GTT offset */ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); +unpin: + i915_gem_object_unpin(obj); unlock: mutex_unlock(&dev->struct_mutex); out: @@ -1707,10 +1696,14 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj) if (obj->pages_pin_count) return -EBUSY; + /* ->put_pages might need to allocate memory for the bit17 swizzle + * array, hence protect them from being reaped by removing them from gtt + * lists early. */ + list_del(&obj->gtt_list); + ops->put_pages(obj); obj->pages = NULL; - list_del(&obj->gtt_list); if (i915_gem_object_is_purgeable(obj)) i915_gem_object_truncate(obj); @@ -1868,11 +1861,11 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj) void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring, - u32 seqno) + struct intel_ring_buffer *ring) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 seqno = intel_ring_get_seqno(ring); BUG_ON(ring == NULL); obj->ring = ring; @@ -1933,26 +1926,54 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) WARN_ON(i915_verify_lists(dev)); } -static u32 -i915_gem_get_seqno(struct drm_device *dev) +static int +i915_gem_handle_seqno_wrap(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; - u32 seqno = dev_priv->next_seqno; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int ret, i, j; - /* reserve 0 for non-seqno */ - if (++dev_priv->next_seqno == 0) - dev_priv->next_seqno = 1; + /* The hardware uses various monotonic 32-bit counters, if we + * detect that they will wraparound we need to idle the GPU + * and reset those counters. + */ + ret = 0; + for_each_ring(ring, dev_priv, i) { + for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) + ret |= ring->sync_seqno[j] != 0; + } + if (ret == 0) + return ret; + + ret = i915_gpu_idle(dev); + if (ret) + return ret; + + i915_gem_retire_requests(dev); + for_each_ring(ring, dev_priv, i) { + for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) + ring->sync_seqno[j] = 0; + } - return seqno; + return 0; } -u32 -i915_gem_next_request_seqno(struct intel_ring_buffer *ring) +int +i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) { - if (ring->outstanding_lazy_request == 0) - ring->outstanding_lazy_request = i915_gem_get_seqno(ring->dev); + struct drm_i915_private *dev_priv = dev->dev_private; + + /* reserve 0 for non-seqno */ + if (dev_priv->next_seqno == 0) { + int ret = i915_gem_handle_seqno_wrap(dev); + if (ret) + return ret; - return ring->outstanding_lazy_request; + dev_priv->next_seqno = 1; + } + + *seqno = dev_priv->next_seqno++; + return 0; } int @@ -1963,7 +1984,6 @@ i915_add_request(struct intel_ring_buffer *ring, drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; u32 request_ring_position; - u32 seqno; int was_empty; int ret; @@ -1982,7 +2002,6 @@ i915_add_request(struct intel_ring_buffer *ring, if (request == NULL) return -ENOMEM; - seqno = i915_gem_next_request_seqno(ring); /* Record the position of the start of the request so that * should we detect the updated seqno part-way through the @@ -1991,15 +2010,13 @@ i915_add_request(struct intel_ring_buffer *ring, */ request_ring_position = intel_ring_get_tail(ring); - ret = ring->add_request(ring, &seqno); + ret = ring->add_request(ring); if (ret) { kfree(request); return ret; } - trace_i915_gem_request_add(ring, seqno); - - request->seqno = seqno; + request->seqno = intel_ring_get_seqno(ring); request->ring = ring; request->tail = request_ring_position; request->emitted_jiffies = jiffies; @@ -2017,23 +2034,24 @@ i915_add_request(struct intel_ring_buffer *ring, spin_unlock(&file_priv->mm.lock); } + trace_i915_gem_request_add(ring, request->seqno); ring->outstanding_lazy_request = 0; if (!dev_priv->mm.suspended) { if (i915_enable_hangcheck) { mod_timer(&dev_priv->hangcheck_timer, - jiffies + - msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } if (was_empty) { queue_delayed_work(dev_priv->wq, - &dev_priv->mm.retire_work, HZ); + &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); intel_mark_busy(dev_priv->dev); } } if (out_seqno) - *out_seqno = seqno; + *out_seqno = request->seqno; return 0; } @@ -2131,7 +2149,6 @@ void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { uint32_t seqno; - int i; if (list_empty(&ring->request_list)) return; @@ -2140,10 +2157,6 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) seqno = ring->get_seqno(ring, true); - for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) - if (seqno >= ring->sync_seqno[i]) - ring->sync_seqno[i] = 0; - while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -2218,7 +2231,8 @@ i915_gem_retire_work_handler(struct work_struct *work) /* Come back later if the device is busy... */ if (!mutex_trylock(&dev->struct_mutex)) { - queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); return; } @@ -2236,7 +2250,8 @@ i915_gem_retire_work_handler(struct work_struct *work) } if (!dev_priv->mm.suspended && !idle) - queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, + round_jiffies_up_relative(HZ)); if (idle) intel_mark_idle(dev); @@ -2386,7 +2401,11 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, ret = to->sync_to(to, from, seqno); if (!ret) - from->sync_seqno[idx] = seqno; + /* We use last_read_seqno because sync_to() + * might have just caused seqno wrap under + * the radar. + */ + from->sync_seqno[idx] = obj->last_read_seqno; return ret; } @@ -2469,14 +2488,6 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) return 0; } -static int i915_ring_idle(struct intel_ring_buffer *ring) -{ - if (list_empty(&ring->active_list)) - return 0; - - return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring)); -} - int i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -2489,7 +2500,7 @@ int i915_gpu_idle(struct drm_device *dev) if (ret) return ret; - ret = i915_ring_idle(ring); + ret = intel_ring_idle(ring); if (ret) return ret; } @@ -2923,13 +2934,14 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, if (ret) return ret; + i915_gem_object_pin_pages(obj); + search_free: if (map_and_fenceable) - free_space = - drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space, - size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end, - false); + free_space = drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space, + size, alignment, obj->cache_level, + 0, dev_priv->mm.gtt_mappable_end, + false); else free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space, size, alignment, obj->cache_level, @@ -2937,60 +2949,60 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, if (free_space != NULL) { if (map_and_fenceable) - obj->gtt_space = + free_space = drm_mm_get_block_range_generic(free_space, size, alignment, obj->cache_level, 0, dev_priv->mm.gtt_mappable_end, false); else - obj->gtt_space = + free_space = drm_mm_get_block_generic(free_space, size, alignment, obj->cache_level, false); } - if (obj->gtt_space == NULL) { + if (free_space == NULL) { ret = i915_gem_evict_something(dev, size, alignment, obj->cache_level, map_and_fenceable, nonblocking); - if (ret) + if (ret) { + i915_gem_object_unpin_pages(obj); return ret; + } goto search_free; } if (WARN_ON(!i915_gem_valid_gtt_space(dev, - obj->gtt_space, + free_space, obj->cache_level))) { - drm_mm_put_block(obj->gtt_space); - obj->gtt_space = NULL; + i915_gem_object_unpin_pages(obj); + drm_mm_put_block(free_space); return -EINVAL; } - ret = i915_gem_gtt_prepare_object(obj); if (ret) { - drm_mm_put_block(obj->gtt_space); - obj->gtt_space = NULL; + i915_gem_object_unpin_pages(obj); + drm_mm_put_block(free_space); return ret; } - if (!dev_priv->mm.aliasing_ppgtt) - i915_gem_gtt_bind_object(obj, obj->cache_level); - list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - obj->gtt_offset = obj->gtt_space->start; + obj->gtt_space = free_space; + obj->gtt_offset = free_space->start; fenceable = - obj->gtt_space->size == fence_size && - (obj->gtt_space->start & (fence_alignment - 1)) == 0; + free_space->size == fence_size && + (free_space->start & (fence_alignment - 1)) == 0; mappable = obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; obj->map_and_fenceable = mappable && fenceable; + i915_gem_object_unpin_pages(obj); trace_i915_gem_object_bind(obj, map_and_fenceable); i915_gem_verify_gtt(dev); return 0; @@ -3059,7 +3071,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) return; i915_gem_clflush_object(obj); - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(obj->base.dev); old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; @@ -3454,11 +3466,16 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, } if (obj->gtt_space == NULL) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + ret = i915_gem_object_bind_to_gtt(obj, alignment, map_and_fenceable, nonblocking); if (ret) return ret; + + if (!dev_priv->mm.aliasing_ppgtt) + i915_gem_gtt_bind_object(obj, obj->cache_level); } if (!obj->has_global_gtt_mapping && map_and_fenceable) @@ -3832,7 +3849,7 @@ void i915_gem_l3_remap(struct drm_device *dev) if (!IS_IVYBRIDGE(dev)) return; - if (!dev_priv->mm.l3_remap_info) + if (!dev_priv->l3_parity.remap_info) return; misccpctl = I915_READ(GEN7_MISCCPCTL); @@ -3841,12 +3858,12 @@ void i915_gem_l3_remap(struct drm_device *dev) for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) { u32 remap = I915_READ(GEN7_L3LOG_BASE + i); - if (remap && remap != dev_priv->mm.l3_remap_info[i/4]) + if (remap && remap != dev_priv->l3_parity.remap_info[i/4]) DRM_DEBUG("0x%x was already programmed to %x\n", GEN7_L3LOG_BASE + i, remap); - if (remap && !dev_priv->mm.l3_remap_info[i/4]) + if (remap && !dev_priv->l3_parity.remap_info[i/4]) DRM_DEBUG_DRIVER("Clearing remapped register\n"); - I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->mm.l3_remap_info[i/4]); + I915_WRITE(GEN7_L3LOG_BASE + i, dev_priv->l3_parity.remap_info[i/4]); } /* Make sure all the writes land before disabling dop clock gating */ @@ -3876,68 +3893,6 @@ void i915_gem_init_swizzling(struct drm_device *dev) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); } -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; - uint32_t __iomem *pd_addr; - uint32_t pd_entry; - int i; - - if (!dev_priv->mm.aliasing_ppgtt) - return; - - - pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t); - for (i = 0; i < ppgtt->num_pd_entries; i++) { - dma_addr_t pt_addr; - - if (dev_priv->mm.gtt->needs_dmar) - pt_addr = ppgtt->pt_dma_addr[i]; - else - pt_addr = page_to_phys(ppgtt->pt_pages[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); - } -} - static bool intel_enable_blt(struct drm_device *dev) { @@ -3960,7 +3915,7 @@ i915_gem_init_hw(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int ret; - if (!intel_enable_gtt()) + if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) return -EIO; if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) @@ -4295,7 +4250,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, page_cache_release(page); } } - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(dev); obj->phys_obj->cur_obj = NULL; obj->phys_obj = NULL; @@ -4382,7 +4337,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, return -EFAULT; } - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(dev); return 0; } @@ -4407,6 +4362,19 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file) spin_unlock(&file_priv->mm.lock); } +static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) +{ + if (!mutex_is_locked(mutex)) + return false; + +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES) + return mutex->owner == task; +#else + /* Since UP may be pre-empted, we cannot assume that we own the lock */ + return false; +#endif +} + static int i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) { @@ -4417,10 +4385,15 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) struct drm_device *dev = dev_priv->dev; struct drm_i915_gem_object *obj; int nr_to_scan = sc->nr_to_scan; + bool unlock = true; int cnt; - if (!mutex_trylock(&dev->struct_mutex)) - return 0; + if (!mutex_trylock(&dev->struct_mutex)) { + if (!mutex_is_locked_by(&dev->struct_mutex, current)) + return 0; + + unlock = false; + } if (nr_to_scan) { nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); @@ -4436,6 +4409,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) if (obj->pin_count == 0 && obj->pages_pin_count == 0) cnt += obj->base.size >> PAGE_SHIFT; - mutex_unlock(&dev->struct_mutex); + if (unlock) + mutex_unlock(&dev->struct_mutex); return cnt; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 05ed42f..a3f06bc 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -146,7 +146,7 @@ create_hw_context(struct drm_device *dev, struct i915_hw_context *ctx; int ret, id; - ctx = kzalloc(sizeof(struct drm_i915_file_private), GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) return ERR_PTR(-ENOMEM); @@ -410,9 +410,8 @@ static int do_switch(struct i915_hw_context *to) * MI_SET_CONTEXT instead of when the next seqno has completed. */ if (from_obj != NULL) { - u32 seqno = i915_gem_next_request_seqno(ring); from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; - i915_gem_object_move_to_active(from_obj, ring, seqno); + i915_gem_object_move_to_active(from_obj, ring); /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the * whole damn pipeline, we don't need to explicitly mark the * object dirty. The only exception is that the context must be diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3eea143..ee8f97f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -128,15 +128,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, target_i915_obj->cache_level); } - /* The target buffer should have appeared before us in the - * exec_object list, so it should have a GTT space bound by now. - */ - if (unlikely(target_offset == 0)) { - DRM_DEBUG("No GTT space found for object %d\n", - reloc->target_handle); - return ret; - } - /* Validate that the target is in a valid r/w GPU domain */ if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { DRM_DEBUG("reloc with multiple write domains: " @@ -672,7 +663,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, } if (flush_domains & I915_GEM_DOMAIN_CPU) - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(ring->dev); if (flush_domains & I915_GEM_DOMAIN_GTT) wmb(); @@ -722,8 +713,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, static void i915_gem_execbuffer_move_to_active(struct list_head *objects, - struct intel_ring_buffer *ring, - u32 seqno) + struct intel_ring_buffer *ring) { struct drm_i915_gem_object *obj; @@ -735,10 +725,10 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, obj->base.write_domain = obj->base.pending_write_domain; obj->fenced_gpu_access = obj->pending_fenced_gpu_access; - i915_gem_object_move_to_active(obj, ring, seqno); + i915_gem_object_move_to_active(obj, ring); if (obj->base.write_domain) { obj->dirty = 1; - obj->last_write_seqno = seqno; + obj->last_write_seqno = intel_ring_get_seqno(ring); if (obj->pin_count) /* check for potential scanout */ intel_mark_fb_busy(obj); } @@ -798,8 +788,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct intel_ring_buffer *ring; u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; - u32 seqno; u32 mask; + u32 flags; int ret, mode, i; if (!i915_gem_check_execbuffer(args)) { @@ -811,6 +801,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) return ret; + flags = 0; + if (args->flags & I915_EXEC_SECURE) { + if (!file->is_master || !capable(CAP_SYS_ADMIN)) + return -EPERM; + + flags |= I915_DISPATCH_SECURE; + } + switch (args->flags & I915_EXEC_RING_MASK) { case I915_EXEC_DEFAULT: case I915_EXEC_RENDER: @@ -983,26 +981,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure + * batch" bit. Hence we need to pin secure batches into the global gtt. + * hsw should have this fixed, but let's be paranoid and do it + * unconditionally for now. */ + if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level); + ret = i915_gem_execbuffer_move_to_gpu(ring, &objects); if (ret) goto err; - seqno = i915_gem_next_request_seqno(ring); - for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) { - if (seqno < ring->sync_seqno[i]) { - /* The GPU can not handle its semaphore value wrapping, - * so every billion or so execbuffers, we need to stall - * the GPU in order to reset the counters. - */ - ret = i915_gpu_idle(dev); - if (ret) - goto err; - i915_gem_retire_requests(dev); - - BUG_ON(ring->sync_seqno[i]); - } - } - ret = i915_switch_context(ring, file, ctx_id); if (ret) goto err; @@ -1028,8 +1017,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - trace_i915_gem_ring_dispatch(ring, seqno); - exec_start = batch_obj->gtt_offset + args->batch_start_offset; exec_len = args->batch_len; if (cliprects) { @@ -1040,17 +1027,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; ret = ring->dispatch_execbuffer(ring, - exec_start, exec_len); + exec_start, exec_len, + flags); if (ret) goto err; } } else { - ret = ring->dispatch_execbuffer(ring, exec_start, exec_len); + ret = ring->dispatch_execbuffer(ring, + exec_start, exec_len, + flags); if (ret) goto err; } - i915_gem_execbuffer_move_to_active(&objects, ring, seqno); + trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); + + i915_gem_execbuffer_move_to_active(&objects, ring); i915_gem_execbuffer_retire_commands(dev, file, ring); err: diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index df470b5..2c150de 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -28,19 +28,67 @@ #include "i915_trace.h" #include "intel_drv.h" +typedef uint32_t gtt_pte_t; + +/* PPGTT stuff */ +#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) + +#define GEN6_PDE_VALID (1 << 0) +/* gen6+ has bit 11-4 for physical addr bit 39-32 */ +#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) + +#define GEN6_PTE_VALID (1 << 0) +#define GEN6_PTE_UNCACHED (1 << 1) +#define HSW_PTE_UNCACHED (0) +#define GEN6_PTE_CACHE_LLC (2 << 1) +#define GEN6_PTE_CACHE_LLC_MLC (3 << 1) +#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) + +static inline gtt_pte_t pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) +{ + gtt_pte_t pte = GEN6_PTE_VALID; + pte |= GEN6_PTE_ADDR_ENCODE(addr); + + switch (level) { + case I915_CACHE_LLC_MLC: + /* Haswell doesn't set L3 this way */ + if (IS_HASWELL(dev)) + pte |= GEN6_PTE_CACHE_LLC; + else + pte |= GEN6_PTE_CACHE_LLC_MLC; + break; + case I915_CACHE_LLC: + pte |= GEN6_PTE_CACHE_LLC; + break; + case I915_CACHE_NONE: + if (IS_HASWELL(dev)) + pte |= HSW_PTE_UNCACHED; + else + pte |= GEN6_PTE_UNCACHED; + break; + default: + BUG(); + } + + + return pte; +} + /* PPGTT support for Sandybdrige/Gen6 and later */ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { - uint32_t *pt_vaddr; - uint32_t scratch_pte; + gtt_pte_t *pt_vaddr; + gtt_pte_t scratch_pte; unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr); - scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC; + scratch_pte = pte_encode(ppgtt->dev, ppgtt->scratch_page_dma_addr, + I915_CACHE_LLC); while (num_entries) { last_pte = first_pte + num_entries; @@ -77,6 +125,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) if (!ppgtt) return ret; + ppgtt->dev = dev; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries, GFP_KERNEL); @@ -118,7 +167,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) i915_ppgtt_clear_range(ppgtt, 0, ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); - ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(uint32_t); + ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); dev_priv->mm.aliasing_ppgtt = ppgtt; @@ -168,9 +217,9 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, const struct sg_table *pages, unsigned first_entry, - uint32_t pte_flags) + enum i915_cache_level cache_level) { - uint32_t *pt_vaddr, pte; + 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; @@ -188,8 +237,8 @@ static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - pte = GEN6_PTE_ADDR_ENCODE(page_addr); - pt_vaddr[j] = pte | pte_flags; + pt_vaddr[j] = pte_encode(ppgtt->dev, page_addr, + cache_level); /* grab the next page */ if (++m == segment_len) { @@ -213,29 +262,10 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { - uint32_t pte_flags = GEN6_PTE_VALID; - - switch (cache_level) { - case I915_CACHE_LLC_MLC: - pte_flags |= GEN6_PTE_CACHE_LLC_MLC; - break; - case I915_CACHE_LLC: - pte_flags |= GEN6_PTE_CACHE_LLC; - break; - case I915_CACHE_NONE: - if (IS_HASWELL(obj->base.dev)) - pte_flags |= HSW_PTE_UNCACHED; - else - pte_flags |= GEN6_PTE_UNCACHED; - break; - default: - BUG(); - } - i915_ppgtt_insert_sg_entries(ppgtt, obj->pages, obj->gtt_space->start >> PAGE_SHIFT, - pte_flags); + cache_level); } void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, @@ -246,23 +276,65 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, obj->base.size >> PAGE_SHIFT); } -/* XXX kill agp_type! */ -static unsigned int cache_level_to_agp_type(struct drm_device *dev, - enum i915_cache_level cache_level) +void i915_gem_init_ppgtt(struct drm_device *dev) { - switch (cache_level) { - case I915_CACHE_LLC_MLC: - if (INTEL_INFO(dev)->gen >= 6) - return AGP_USER_CACHED_MEMORY_LLC_MLC; - /* Older chipsets do not have this extra level of CPU - * cacheing, so fallthrough and request the PTE simply - * as cached. - */ - case I915_CACHE_LLC: - return AGP_USER_CACHED_MEMORY; - default: - case I915_CACHE_NONE: - return AGP_USER_MEMORY; + 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; + uint32_t __iomem *pd_addr; + uint32_t pd_entry; + int i; + + if (!dev_priv->mm.aliasing_ppgtt) + return; + + + pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t); + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; + + if (dev_priv->mm.gtt->needs_dmar) + pt_addr = ppgtt->pt_dma_addr[i]; + else + pt_addr = page_to_phys(ppgtt->pt_pages[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); } } @@ -288,13 +360,40 @@ static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible) dev_priv->mm.interruptible = interruptible; } + +static void i915_ggtt_clear_range(struct drm_device *dev, + unsigned first_entry, + unsigned num_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + gtt_pte_t scratch_pte; + gtt_pte_t __iomem *gtt_base = dev_priv->mm.gtt->gtt + first_entry; + const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; + int i; + + if (INTEL_INFO(dev)->gen < 6) { + intel_gtt_clear_range(first_entry, num_entries); + return; + } + + if (WARN(num_entries > max_entries, + "First entry = %d; Num entries = %d (max=%d)\n", + first_entry, num_entries, max_entries)) + num_entries = max_entries; + + scratch_pte = pte_encode(dev, dev_priv->mm.gtt->scratch_page_dma, I915_CACHE_LLC); + for (i = 0; i < num_entries; i++) + iowrite32(scratch_pte, >t_base[i]); + readl(gtt_base); +} + void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; /* First fill our portion of the GTT with scratch pages */ - intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE, + i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE, (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { @@ -302,7 +401,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) i915_gem_gtt_bind_object(obj, obj->cache_level); } - intel_gtt_chipset_flush(); + i915_gem_chipset_flush(dev); } int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) @@ -318,21 +417,76 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) return 0; } +/* + * Binds an object into the global gtt with the specified cache level. The object + * will be accessible to the GPU via commands whose operands reference offsets + * within the global GTT as well as accessible by the GPU through the GMADR + * mapped BAR (dev_priv->mm.gtt->gtt). + */ +static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, + enum i915_cache_level level) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct sg_table *st = obj->pages; + struct scatterlist *sg = st->sgl; + const int first_entry = obj->gtt_space->start >> PAGE_SHIFT; + const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; + gtt_pte_t __iomem *gtt_entries = dev_priv->mm.gtt->gtt + first_entry; + int unused, i = 0; + unsigned int len, m = 0; + 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(pte_encode(dev, addr, level), >t_entries[i]); + i++; + } + } + + BUG_ON(i > max_entries); + BUG_ON(i != obj->base.size / PAGE_SIZE); + + /* XXX: This serves as a posting read to make sure that the PTE has + * actually been updated. There is some concern that even though + * registers and PTEs are within the same BAR that they are potentially + * of NUMA access patterns. Therefore, even with the way we assume + * hardware should work, we must keep this posting read for paranoia. + */ + if (i != 0) + WARN_ON(readl(>t_entries[i-1]) != pte_encode(dev, addr, level)); + + /* This next bit makes the above posting read even more important. We + * want to flush the TLBs only after we're certain all the PTE updates + * have finished. + */ + I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); + POSTING_READ(GFX_FLSH_CNTL_GEN6); +} + void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) { struct drm_device *dev = obj->base.dev; - unsigned int agp_type = cache_level_to_agp_type(dev, cache_level); + if (INTEL_INFO(dev)->gen < 6) { + unsigned int flags = (cache_level == I915_CACHE_NONE) ? + AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; + intel_gtt_insert_sg_entries(obj->pages, + obj->gtt_space->start >> PAGE_SHIFT, + flags); + } else { + gen6_ggtt_bind_object(obj, cache_level); + } - intel_gtt_insert_sg_entries(obj->pages, - obj->gtt_space->start >> PAGE_SHIFT, - agp_type); obj->has_global_gtt_mapping = 1; } void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) { - intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, + i915_ggtt_clear_range(obj->base.dev, + obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT); obj->has_global_gtt_mapping = 0; @@ -390,5 +544,165 @@ void i915_gem_init_global_gtt(struct drm_device *dev, dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; /* ... but ensure that we clear the entire range. */ - intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); + i915_ggtt_clear_range(dev, start / PAGE_SIZE, (end-start) / PAGE_SIZE); +} + +static int setup_scratch_page(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct page *page; + dma_addr_t dma_addr; + + page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); + if (page == NULL) + return -ENOMEM; + get_page(page); + set_pages_uc(page, 1); + +#ifdef CONFIG_INTEL_IOMMU + dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(dev->pdev, dma_addr)) + return -EINVAL; +#else + dma_addr = page_to_phys(page); +#endif + dev_priv->mm.gtt->scratch_page = page; + dev_priv->mm.gtt->scratch_page_dma = dma_addr; + + return 0; +} + +static void teardown_scratch_page(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + set_pages_wb(dev_priv->mm.gtt->scratch_page, 1); + pci_unmap_page(dev->pdev, dev_priv->mm.gtt->scratch_page_dma, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + put_page(dev_priv->mm.gtt->scratch_page); + __free_page(dev_priv->mm.gtt->scratch_page); +} + +static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) +{ + snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT; + snb_gmch_ctl &= SNB_GMCH_GGMS_MASK; + return snb_gmch_ctl << 20; +} + +static inline unsigned int gen6_get_stolen_size(u16 snb_gmch_ctl) +{ + snb_gmch_ctl >>= SNB_GMCH_GMS_SHIFT; + snb_gmch_ctl &= SNB_GMCH_GMS_MASK; + return snb_gmch_ctl << 25; /* 32 MB units */ +} + +static inline unsigned int gen7_get_stolen_size(u16 snb_gmch_ctl) +{ + static const int stolen_decoder[] = { + 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352}; + snb_gmch_ctl >>= IVB_GMCH_GMS_SHIFT; + snb_gmch_ctl &= IVB_GMCH_GMS_MASK; + return stolen_decoder[snb_gmch_ctl] << 20; +} + +int i915_gem_gtt_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + phys_addr_t gtt_bus_addr; + u16 snb_gmch_ctl; + int ret; + + /* On modern platforms we need not worry ourself with the legacy + * hostbridge query stuff. Skip it entirely + */ + if (INTEL_INFO(dev)->gen < 6) { + ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL); + if (!ret) { + DRM_ERROR("failed to set up gmch\n"); + return -EIO; + } + + dev_priv->mm.gtt = intel_gtt_get(); + if (!dev_priv->mm.gtt) { + DRM_ERROR("Failed to initialize GTT\n"); + intel_gmch_remove(); + return -ENODEV; + } + return 0; + } + + dev_priv->mm.gtt = kzalloc(sizeof(*dev_priv->mm.gtt), GFP_KERNEL); + if (!dev_priv->mm.gtt) + return -ENOMEM; + + if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(40))) + pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(40)); + +#ifdef CONFIG_INTEL_IOMMU + dev_priv->mm.gtt->needs_dmar = 1; +#endif + + /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ + gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); + dev_priv->mm.gtt->gma_bus_addr = pci_resource_start(dev->pdev, 2); + + /* i9xx_setup */ + pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); + dev_priv->mm.gtt->gtt_total_entries = + gen6_get_total_gtt_size(snb_gmch_ctl) / sizeof(gtt_pte_t); + if (INTEL_INFO(dev)->gen < 7) + dev_priv->mm.gtt->stolen_size = gen6_get_stolen_size(snb_gmch_ctl); + else + dev_priv->mm.gtt->stolen_size = gen7_get_stolen_size(snb_gmch_ctl); + + dev_priv->mm.gtt->gtt_mappable_entries = pci_resource_len(dev->pdev, 2) >> PAGE_SHIFT; + /* 64/512MB is the current min/max we actually know of, but this is just a + * coarse sanity check. + */ + if ((dev_priv->mm.gtt->gtt_mappable_entries >> 8) < 64 || + dev_priv->mm.gtt->gtt_mappable_entries > dev_priv->mm.gtt->gtt_total_entries) { + DRM_ERROR("Unknown GMADR entries (%d)\n", + dev_priv->mm.gtt->gtt_mappable_entries); + ret = -ENXIO; + goto err_out; + } + + ret = setup_scratch_page(dev); + if (ret) { + DRM_ERROR("Scratch setup failed\n"); + goto err_out; + } + + dev_priv->mm.gtt->gtt = ioremap_wc(gtt_bus_addr, + dev_priv->mm.gtt->gtt_total_entries * sizeof(gtt_pte_t)); + if (!dev_priv->mm.gtt->gtt) { + DRM_ERROR("Failed to map the gtt page table\n"); + teardown_scratch_page(dev); + ret = -ENOMEM; + goto err_out; + } + + /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */ + DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8); + DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8); + DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20); + + return 0; + +err_out: + kfree(dev_priv->mm.gtt); + if (INTEL_INFO(dev)->gen < 6) + intel_gmch_remove(); + return ret; +} + +void i915_gem_gtt_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + iounmap(dev_priv->mm.gtt->gtt); + teardown_scratch_page(dev); + if (INTEL_INFO(dev)->gen < 6) + intel_gmch_remove(); + kfree(dev_priv->mm.gtt); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 32e1bda..a4dc97f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -122,7 +122,10 @@ static int i915_pipe_enabled(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + + return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE; } /* Called from drm generic code, passed a 'crtc', which @@ -182,6 +185,8 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, int vbl_start, vbl_end, htotal, vtotal; bool in_vbl = true; int ret = 0; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " @@ -190,7 +195,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, } /* Get vtotal. */ - vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff); + vtotal = 1 + ((I915_READ(VTOTAL(cpu_transcoder)) >> 16) & 0x1fff); if (INTEL_INFO(dev)->gen >= 4) { /* No obvious pixelcount register. Only query vertical @@ -210,13 +215,13 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, */ position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; - htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff); + htotal = 1 + ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff); *vpos = position / htotal; *hpos = position - (*vpos * htotal); } /* Query vblank area. */ - vbl = I915_READ(VBLANK(pipe)); + vbl = I915_READ(VBLANK(cpu_transcoder)); /* Test position against vblank region. */ vbl_start = vbl & 0x1fff; @@ -352,8 +357,7 @@ static void notify_ring(struct drm_device *dev, if (i915_enable_hangcheck) { dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, - jiffies + - msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } } @@ -374,7 +378,7 @@ static void gen6_pm_rps_work(struct work_struct *work) if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) return; - mutex_lock(&dev_priv->dev->struct_mutex); + mutex_lock(&dev_priv->rps.hw_lock); if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) new_delay = dev_priv->rps.cur_delay + 1; @@ -389,7 +393,7 @@ static void gen6_pm_rps_work(struct work_struct *work) gen6_set_rps(dev_priv->dev, new_delay); } - mutex_unlock(&dev_priv->dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); } @@ -405,7 +409,7 @@ static void gen6_pm_rps_work(struct work_struct *work) static void ivybridge_parity_work(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - parity_error_work); + l3_parity.error_work); u32 error_status, row, bank, subbank; char *parity_event[5]; uint32_t misccpctl; @@ -469,7 +473,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev) I915_WRITE(GTIMR, dev_priv->gt_irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, flags); - queue_work(dev_priv->wq, &dev_priv->parity_error_work); + queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work); } static void snb_gt_irq_handler(struct drm_device *dev, @@ -520,7 +524,7 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, queue_work(dev_priv->wq, &dev_priv->rps.work); } -static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t valleyview_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; @@ -606,6 +610,9 @@ 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; + if (pch_iir & SDE_HOTPLUG_MASK) + 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) >> @@ -646,6 +653,9 @@ 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; + if (pch_iir & SDE_HOTPLUG_MASK_CPT) + 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) >> @@ -670,7 +680,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) I915_READ(FDI_RX_IIR(pipe))); } -static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) +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; @@ -709,8 +719,6 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) if (de_iir & DE_PCH_EVENT_IVB) { u32 pch_iir = I915_READ(SDEIIR); - if (pch_iir & SDE_HOTPLUG_MASK_CPT) - queue_work(dev_priv->wq, &dev_priv->hotplug_work); cpt_irq_handler(dev, pch_iir); /* clear PCH hotplug event before clear CPU irq */ @@ -745,13 +753,12 @@ static void ilk_gt_irq_handler(struct drm_device *dev, notify_ring(dev, &dev_priv->ring[VCS]); } -static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t ironlake_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; int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; - u32 hotplug_mask; atomic_inc(&dev_priv->irq_received); @@ -769,11 +776,6 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) (!IS_GEN6(dev) || pm_iir == 0)) goto done; - if (HAS_PCH_CPT(dev)) - hotplug_mask = SDE_HOTPLUG_MASK_CPT; - else - hotplug_mask = SDE_HOTPLUG_MASK; - ret = IRQ_HANDLED; if (IS_GEN5(dev)) @@ -802,8 +804,6 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) /* check event from PCH */ if (de_iir & DE_PCH_EVENT) { - if (pch_iir & hotplug_mask) - queue_work(dev_priv->wq, &dev_priv->hotplug_work); if (HAS_PCH_CPT(dev)) cpt_irq_handler(dev, pch_iir); else @@ -1120,6 +1120,8 @@ static void i915_record_ring_state(struct drm_device *dev, = I915_READ(RING_SYNC_0(ring->mmio_base)); error->semaphore_mboxes[ring->id][1] = I915_READ(RING_SYNC_1(ring->mmio_base)); + error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0]; + error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1]; } if (INTEL_INFO(dev)->gen >= 4) { @@ -1464,7 +1466,9 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; - if (work == NULL || work->pending || !work->enable_stall_check) { + if (work == NULL || + atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE || + !work->enable_stall_check) { /* Either the pending flip IRQ arrived, or we're too early. Don't check */ spin_unlock_irqrestore(&dev->event_lock, flags); return; @@ -1751,7 +1755,7 @@ void i915_hangcheck_elapsed(unsigned long data) repeat: /* Reset timer case chip hangs without another request being added */ mod_timer(&dev_priv->hangcheck_timer, - jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } /* drm_dma.h hooks @@ -1956,6 +1960,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev) u32 enable_mask; u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; + u32 render_irqs; u16 msid; enable_mask = I915_DISPLAY_PORT_INTERRUPT; @@ -1995,21 +2000,12 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IIR, 0xffffffff); - dev_priv->gt_irq_mask = ~0; - - I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - I915_WRITE(GTIER, GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT | - GT_GEN6_BLT_CS_ERROR_INTERRUPT | - GT_GEN6_BLT_USER_INTERRUPT | - GT_GEN6_BSD_USER_INTERRUPT | - GT_GEN6_BSD_CS_ERROR_INTERRUPT | - GT_GEN7_L3_PARITY_ERROR_INTERRUPT | - GT_PIPE_NOTIFY | - GT_RENDER_CS_ERROR_INTERRUPT | - GT_SYNC_STATUS | - GT_USER_INTERRUPT); + + render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT | + GEN6_BLITTER_USER_INTERRUPT; + I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); /* ack & enable invalid PTE error interrupts */ @@ -2019,7 +2015,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) #endif I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); -#if 0 /* FIXME: check register definitions; some have moved */ /* Note HDMI and DP share bits */ if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) hotplug_en |= HDMIB_HOTPLUG_INT_EN; @@ -2027,15 +2022,14 @@ static int valleyview_irq_postinstall(struct drm_device *dev) hotplug_en |= HDMIC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) hotplug_en |= HDMID_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) + 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) + 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; } -#endif I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); @@ -2129,7 +2123,7 @@ static int i8xx_irq_postinstall(struct drm_device *dev) return 0; } -static irqreturn_t i8xx_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t i8xx_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; @@ -2307,7 +2301,7 @@ static int i915_irq_postinstall(struct drm_device *dev) return 0; } -static irqreturn_t i915_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t i915_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; @@ -2545,7 +2539,7 @@ static int i965_irq_postinstall(struct drm_device *dev) return 0; } -static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS) +static irqreturn_t i965_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; @@ -2691,7 +2685,7 @@ void intel_irq_init(struct drm_device *dev) INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); INIT_WORK(&dev_priv->error_work, i915_error_work_func); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); - INIT_WORK(&dev_priv->parity_error_work, ivybridge_parity_work); + INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a4162dd..3f75cfa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -26,6 +26,7 @@ #define _I915_REG_H_ #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a))) #define _PORT(port, a, b) ((a) + (port)*((b)-(a))) @@ -40,6 +41,14 @@ */ #define INTEL_GMCH_CTRL 0x52 #define INTEL_GMCH_VGA_DISABLE (1 << 1) +#define SNB_GMCH_CTRL 0x50 +#define SNB_GMCH_GGMS_SHIFT 8 /* GTT Graphics Memory Size */ +#define SNB_GMCH_GGMS_MASK 0x3 +#define SNB_GMCH_GMS_SHIFT 3 /* Graphics Mode Select */ +#define SNB_GMCH_GMS_MASK 0x1f +#define IVB_GMCH_GMS_SHIFT 4 +#define IVB_GMCH_GMS_MASK 0xf + /* PCI config space */ @@ -105,23 +114,6 @@ #define GEN6_GRDOM_MEDIA (1 << 2) #define GEN6_GRDOM_BLT (1 << 3) -/* PPGTT stuff */ -#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) - -#define GEN6_PDE_VALID (1 << 0) -#define GEN6_PDE_LARGE_PAGE (2 << 0) /* use 32kb pages */ -/* gen6+ has bit 11-4 for physical addr bit 39-32 */ -#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) - -#define GEN6_PTE_VALID (1 << 0) -#define GEN6_PTE_UNCACHED (1 << 1) -#define HSW_PTE_UNCACHED (0) -#define GEN6_PTE_CACHE_LLC (2 << 1) -#define GEN6_PTE_CACHE_LLC_MLC (3 << 1) -#define GEN6_PTE_CACHE_BITS (3 << 1) -#define GEN6_PTE_GFDT (1 << 3) -#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) - #define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228) #define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518) #define RING_PP_DIR_DCLV(ring) ((ring)->mmio_base+0x220) @@ -241,11 +233,18 @@ */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) #define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ -#define MI_INVALIDATE_TLB (1<<18) -#define MI_INVALIDATE_BSD (1<<7) +#define MI_FLUSH_DW_STORE_INDEX (1<<21) +#define MI_INVALIDATE_TLB (1<<18) +#define MI_FLUSH_DW_OP_STOREDW (1<<14) +#define MI_INVALIDATE_BSD (1<<7) +#define MI_FLUSH_DW_USE_GTT (1<<2) +#define MI_FLUSH_DW_USE_PPGTT (0<<2) #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) -#define MI_BATCH_NON_SECURE (1) -#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_NON_SECURE (1) +/* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ +#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_PPGTT_HSW (1<<8) +#define MI_BATCH_NON_SECURE_HSW (1<<13) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) #define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ @@ -369,6 +368,7 @@ #define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */ #define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */ #define DPIO_PLL_REFCLK_SEL_SHIFT 16 /* 2 bits */ +#define DPIO_PLL_REFCLK_SEL_MASK 3 #define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */ #define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */ #define _DPIO_REFSFR_B 0x8034 @@ -384,6 +384,9 @@ #define DPIO_FASTCLK_DISABLE 0x8100 +#define DPIO_DATA_CHANNEL1 0x8220 +#define DPIO_DATA_CHANNEL2 0x8420 + /* * Fence registers */ @@ -521,6 +524,7 @@ */ # define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) #define _3D_CHICKEN3 0x02090 +#define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) #define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5) #define MI_MODE 0x0209c @@ -547,6 +551,8 @@ #define IIR 0x020a4 #define IMR 0x020a8 #define ISR 0x020ac +#define VLV_GUNIT_CLOCK_GATE 0x182060 +#define GCFG_DIS (1<<8) #define VLV_IIR_RW 0x182084 #define VLV_IER 0x1820a0 #define VLV_IIR 0x1820a4 @@ -661,6 +667,7 @@ #define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */ #define CACHE_MODE_0 0x02120 /* 915+ only */ +#define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1<<8) #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) #define CM0_STC_EVICT_DISABLE_LRA_SNB (1<<5) @@ -670,6 +677,8 @@ #define CM0_RC_OP_FLUSH_DISABLE (1<<0) #define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ +#define GFX_FLSH_CNTL_GEN6 0x101008 +#define GFX_FLSH_CNTL_EN (1<<0) #define ECOSKPD 0x021d0 #define ECO_GATING_CX_ONLY (1<<3) #define ECO_FLIP_DONE (1<<0) @@ -1559,14 +1568,14 @@ #define _VSYNCSHIFT_B 0x61028 -#define HTOTAL(pipe) _PIPE(pipe, _HTOTAL_A, _HTOTAL_B) -#define HBLANK(pipe) _PIPE(pipe, _HBLANK_A, _HBLANK_B) -#define HSYNC(pipe) _PIPE(pipe, _HSYNC_A, _HSYNC_B) -#define VTOTAL(pipe) _PIPE(pipe, _VTOTAL_A, _VTOTAL_B) -#define VBLANK(pipe) _PIPE(pipe, _VBLANK_A, _VBLANK_B) -#define VSYNC(pipe) _PIPE(pipe, _VSYNC_A, _VSYNC_B) +#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) +#define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B) +#define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B) +#define VTOTAL(trans) _TRANSCODER(trans, _VTOTAL_A, _VTOTAL_B) +#define VBLANK(trans) _TRANSCODER(trans, _VBLANK_A, _VBLANK_B) +#define VSYNC(trans) _TRANSCODER(trans, _VSYNC_A, _VSYNC_B) #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B) -#define VSYNCSHIFT(pipe) _PIPE(pipe, _VSYNCSHIFT_A, _VSYNCSHIFT_B) +#define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B) /* VGA port control */ #define ADPA 0x61100 @@ -2641,6 +2650,7 @@ #define PIPECONF_GAMMA (1<<24) #define PIPECONF_FORCE_BORDER (1<<25) #define PIPECONF_INTERLACE_MASK (7 << 21) +#define PIPECONF_INTERLACE_MASK_HSW (3 << 21) /* Note that pre-gen3 does not support interlaced display directly. Panel * fitting must be disabled on pre-ilk for interlaced. */ #define PIPECONF_PROGRESSIVE (0 << 21) @@ -2711,7 +2721,7 @@ #define PIPE_12BPC (3 << 5) #define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC) -#define PIPECONF(pipe) _PIPE(pipe, _PIPEACONF, _PIPEBCONF) +#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF) #define PIPEDSL(pipe) _PIPE(pipe, _PIPEADSL, _PIPEBDSL) #define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH) #define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) @@ -2998,12 +3008,19 @@ #define DISPPLANE_GAMMA_ENABLE (1<<30) #define DISPPLANE_GAMMA_DISABLE 0 #define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_YUV422 (0x0<<26) #define DISPPLANE_8BPP (0x2<<26) -#define DISPPLANE_15_16BPP (0x4<<26) -#define DISPPLANE_16BPP (0x5<<26) -#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) -#define DISPPLANE_32BPP (0x7<<26) -#define DISPPLANE_32BPP_30BIT_NO_ALPHA (0xa<<26) +#define DISPPLANE_BGRA555 (0x3<<26) +#define DISPPLANE_BGRX555 (0x4<<26) +#define DISPPLANE_BGRX565 (0x5<<26) +#define DISPPLANE_BGRX888 (0x6<<26) +#define DISPPLANE_BGRA888 (0x7<<26) +#define DISPPLANE_RGBX101010 (0x8<<26) +#define DISPPLANE_RGBA101010 (0x9<<26) +#define DISPPLANE_BGRX101010 (0xa<<26) +#define DISPPLANE_RGBX161616 (0xc<<26) +#define DISPPLANE_RGBX888 (0xe<<26) +#define DISPPLANE_RGBA888 (0xf<<26) #define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_DISABLE 0 #define DISPPLANE_SEL_PIPE_SHIFT 24 @@ -3024,6 +3041,8 @@ #define _DSPASIZE 0x70190 #define _DSPASURF 0x7019C /* 965+ only */ #define _DSPATILEOFF 0x701A4 /* 965+ only */ +#define _DSPAOFFSET 0x701A4 /* HSW */ +#define _DSPASURFLIVE 0x701AC #define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) #define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) @@ -3033,6 +3052,8 @@ #define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF) #define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF) #define DSPLINOFF(plane) DSPADDR(plane) +#define DSPOFFSET(plane) _PIPE(plane, _DSPAOFFSET, _DSPBOFFSET) +#define DSPSURFLIVE(plane) _PIPE(plane, _DSPASURFLIVE, _DSPBSURFLIVE) /* Display/Sprite base address macros */ #define DISP_BASEADDR_MASK (0xfffff000) @@ -3078,6 +3099,8 @@ #define _DSPBSIZE 0x71190 #define _DSPBSURF 0x7119C #define _DSPBTILEOFF 0x711A4 +#define _DSPBOFFSET 0x711A4 +#define _DSPBSURFLIVE 0x711AC /* Sprite A control */ #define _DVSACNTR 0x72180 @@ -3143,6 +3166,7 @@ #define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF) #define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL) #define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK) +#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE) #define _SPRA_CTL 0x70280 #define SPRITE_ENABLE (1<<31) @@ -3177,6 +3201,8 @@ #define _SPRA_SURF 0x7029c #define _SPRA_KEYMAX 0x702a0 #define _SPRA_TILEOFF 0x702a4 +#define _SPRA_OFFSET 0x702a4 +#define _SPRA_SURFLIVE 0x702ac #define _SPRA_SCALE 0x70304 #define SPRITE_SCALE_ENABLE (1<<31) #define SPRITE_FILTER_MASK (3<<29) @@ -3197,6 +3223,8 @@ #define _SPRB_SURF 0x7129c #define _SPRB_KEYMAX 0x712a0 #define _SPRB_TILEOFF 0x712a4 +#define _SPRB_OFFSET 0x712a4 +#define _SPRB_SURFLIVE 0x712ac #define _SPRB_SCALE 0x71304 #define _SPRB_GAMC 0x71400 @@ -3210,8 +3238,10 @@ #define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF) #define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX) #define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF) +#define SPROFFSET(pipe) _PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET) #define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE) #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) +#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) /* VBIOS regs */ #define VGACNTRL 0x71400 @@ -3246,12 +3276,6 @@ #define DISPLAY_PORT_PLL_BIOS_1 0x46010 #define DISPLAY_PORT_PLL_BIOS_2 0x46014 -#define PCH_DSPCLK_GATE_D 0x42020 -# define DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9) -# define DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8) -# define DPFDUNIT_CLOCK_GATE_DISABLE (1 << 7) -# define DPARBUNIT_CLOCK_GATE_DISABLE (1 << 5) - #define PCH_3DCGDIS0 0x46020 # define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18) # define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1) @@ -3301,20 +3325,22 @@ #define _PIPEB_LINK_M2 0x61048 #define _PIPEB_LINK_N2 0x6104c -#define PIPE_DATA_M1(pipe) _PIPE(pipe, _PIPEA_DATA_M1, _PIPEB_DATA_M1) -#define PIPE_DATA_N1(pipe) _PIPE(pipe, _PIPEA_DATA_N1, _PIPEB_DATA_N1) -#define PIPE_DATA_M2(pipe) _PIPE(pipe, _PIPEA_DATA_M2, _PIPEB_DATA_M2) -#define PIPE_DATA_N2(pipe) _PIPE(pipe, _PIPEA_DATA_N2, _PIPEB_DATA_N2) -#define PIPE_LINK_M1(pipe) _PIPE(pipe, _PIPEA_LINK_M1, _PIPEB_LINK_M1) -#define PIPE_LINK_N1(pipe) _PIPE(pipe, _PIPEA_LINK_N1, _PIPEB_LINK_N1) -#define PIPE_LINK_M2(pipe) _PIPE(pipe, _PIPEA_LINK_M2, _PIPEB_LINK_M2) -#define PIPE_LINK_N2(pipe) _PIPE(pipe, _PIPEA_LINK_N2, _PIPEB_LINK_N2) +#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1) +#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1) +#define PIPE_DATA_M2(tran) _TRANSCODER(tran, _PIPEA_DATA_M2, _PIPEB_DATA_M2) +#define PIPE_DATA_N2(tran) _TRANSCODER(tran, _PIPEA_DATA_N2, _PIPEB_DATA_N2) +#define PIPE_LINK_M1(tran) _TRANSCODER(tran, _PIPEA_LINK_M1, _PIPEB_LINK_M1) +#define PIPE_LINK_N1(tran) _TRANSCODER(tran, _PIPEA_LINK_N1, _PIPEB_LINK_N1) +#define PIPE_LINK_M2(tran) _TRANSCODER(tran, _PIPEA_LINK_M2, _PIPEB_LINK_M2) +#define PIPE_LINK_N2(tran) _TRANSCODER(tran, _PIPEA_LINK_N2, _PIPEB_LINK_N2) /* CPU panel fitter */ /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */ #define _PFA_CTL_1 0x68080 #define _PFB_CTL_1 0x68880 #define PF_ENABLE (1<<31) +#define PF_PIPE_SEL_MASK_IVB (3<<29) +#define PF_PIPE_SEL_IVB(pipe) ((pipe)<<29) #define PF_FILTER_MASK (3<<23) #define PF_FILTER_PROGRAMMED (0<<23) #define PF_FILTER_MED_3x3 (1<<23) @@ -3423,15 +3449,13 @@ #define ILK_HDCP_DISABLE (1<<25) #define ILK_eDP_A_DISABLE (1<<24) #define ILK_DESKTOP (1<<23) -#define ILK_DSPCLK_GATE 0x42020 -#define IVB_VRHUNIT_CLK_GATE (1<<28) -#define ILK_DPARB_CLK_GATE (1<<5) -#define ILK_DPFD_CLK_GATE (1<<7) -/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */ -#define ILK_CLK_FBC (1<<7) -#define ILK_DPFC_DIS1 (1<<8) -#define ILK_DPFC_DIS2 (1<<9) +#define ILK_DSPCLK_GATE_D 0x42020 +#define ILK_VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) +#define ILK_DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9) +#define ILK_DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8) +#define ILK_DPFDUNIT_CLOCK_GATE_ENABLE (1 << 7) +#define ILK_DPARBUNIT_CLOCK_GATE_ENABLE (1 << 5) #define IVB_CHICKEN3 0x4200c # define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5) @@ -3447,14 +3471,21 @@ #define GEN7_L3CNTLREG1 0xB01C #define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C4FFF8C +#define GEN7_L3AGDIS (1<<19) #define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 #define GEN7_WA_L3_CHICKEN_MODE 0x20000000 +#define GEN7_L3SQCREG4 0xb034 +#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) + /* WaCatErrorRejectionIssue */ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) +#define HSW_FUSE_STRAP 0x42014 +#define HSW_CDCLK_LIMIT (1 << 24) + /* PCH */ /* south display engine interrupt: IBX */ @@ -3686,7 +3717,7 @@ #define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) #define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) -#define VLV_VIDEO_DIP_CTL_A 0x60220 +#define VLV_VIDEO_DIP_CTL_A 0x60200 #define VLV_VIDEO_DIP_DATA_A 0x60208 #define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210 @@ -3795,18 +3826,26 @@ #define TRANS_6BPC (2<<5) #define TRANS_12BPC (3<<5) +#define _TRANSA_CHICKEN1 0xf0060 +#define _TRANSB_CHICKEN1 0xf1060 +#define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) +#define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4) #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) -#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31) +#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) + #define SOUTH_CHICKEN1 0xc2000 #define FDIA_PHASE_SYNC_SHIFT_OVR 19 #define FDIA_PHASE_SYNC_SHIFT_EN 18 -#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) -#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) +#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) +#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) +#define FDI_BC_BIFURCATION_SELECT (1 << 12) #define SOUTH_CHICKEN2 0xc2004 -#define DPLS_EDP_PPS_FIX_DIS (1<<0) +#define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13) +#define FDI_MPHY_IOSFSB_RESET_CTL (1<<12) +#define DPLS_EDP_PPS_FIX_DIS (1<<0) #define _FDI_RXA_CHICKEN 0xc200c #define _FDI_RXB_CHICKEN 0xc2010 @@ -3816,6 +3855,7 @@ #define SOUTH_DSPCLK_GATE_D 0xc2020 #define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) +#define PCH_LP_PARTITION_LEVEL_DISABLE (1<<12) /* CPU: FDI_TX */ #define _FDI_TXA_CTL 0x60100 @@ -3877,6 +3917,7 @@ #define FDI_FS_ERRC_ENABLE (1<<27) #define FDI_FE_ERRC_ENABLE (1<<26) #define FDI_DP_PORT_WIDTH_X8 (7<<19) +#define FDI_RX_POLARITY_REVERSED_LPT (1<<16) #define FDI_8BPC (0<<16) #define FDI_10BPC (1<<16) #define FDI_6BPC (2<<16) @@ -3901,16 +3942,21 @@ #define FDI_PORT_WIDTH_2X_LPT (1<<19) #define FDI_PORT_WIDTH_1X_LPT (0<<19) -#define _FDI_RXA_MISC 0xf0010 -#define _FDI_RXB_MISC 0xf1010 +#define _FDI_RXA_MISC 0xf0010 +#define _FDI_RXB_MISC 0xf1010 +#define FDI_RX_PWRDN_LANE1_MASK (3<<26) +#define FDI_RX_PWRDN_LANE1_VAL(x) ((x)<<26) +#define FDI_RX_PWRDN_LANE0_MASK (3<<24) +#define FDI_RX_PWRDN_LANE0_VAL(x) ((x)<<24) +#define FDI_RX_TP1_TO_TP2_48 (2<<20) +#define FDI_RX_TP1_TO_TP2_64 (3<<20) +#define FDI_RX_FDI_DELAY_90 (0x90<<0) +#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) + #define _FDI_RXA_TUSIZE1 0xf0030 #define _FDI_RXA_TUSIZE2 0xf0038 #define _FDI_RXB_TUSIZE1 0xf1030 #define _FDI_RXB_TUSIZE2 0xf1038 -#define FDI_RX_TP1_TO_TP2_48 (2<<20) -#define FDI_RX_TP1_TO_TP2_64 (3<<20) -#define FDI_RX_FDI_DELAY_90 (0x90<<0) -#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) #define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1) #define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2) @@ -4003,6 +4049,11 @@ #define PANEL_LIGHT_ON_DELAY_SHIFT 0 #define PCH_PP_OFF_DELAYS 0xc720c +#define PANEL_POWER_PORT_SELECT_MASK (0x3 << 30) +#define PANEL_POWER_PORT_LVDS (0 << 30) +#define PANEL_POWER_PORT_DP_A (1 << 30) +#define PANEL_POWER_PORT_DP_C (2 << 30) +#define PANEL_POWER_PORT_DP_D (3 << 30) #define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000) #define PANEL_POWER_DOWN_DELAY_SHIFT 16 #define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff) @@ -4050,7 +4101,7 @@ #define TRANS_DP_CTL_A 0xe0300 #define TRANS_DP_CTL_B 0xe1300 #define TRANS_DP_CTL_C 0xe2300 -#define TRANS_DP_CTL(pipe) (TRANS_DP_CTL_A + (pipe) * 0x01000) +#define TRANS_DP_CTL(pipe) _PIPE(pipe, TRANS_DP_CTL_A, TRANS_DP_CTL_B) #define TRANS_DP_OUTPUT_ENABLE (1<<31) #define TRANS_DP_PORT_SEL_B (0<<29) #define TRANS_DP_PORT_SEL_C (1<<29) @@ -4108,6 +4159,8 @@ #define FORCEWAKE_ACK_HSW 0x130044 #define FORCEWAKE_ACK 0x130090 #define FORCEWAKE_MT 0xa188 /* multi-threaded */ +#define FORCEWAKE_KERNEL 0x1 +#define FORCEWAKE_USER 0x2 #define FORCEWAKE_MT_ACK 0x130040 #define ECOBUS 0xa180 #define FORCEWAKE_MT_ENABLE (1<<5) @@ -4220,6 +4273,10 @@ #define GEN6_READ_OC_PARAMS 0xc #define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 #define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 +#define GEN6_PCODE_WRITE_RC6VIDS 0x4 +#define GEN6_PCODE_READ_RC6VIDS 0x5 +#define GEN6_ENCODE_RC6_VID(mv) (((mv) / 5) - 245) < 0 ?: 0 +#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) > 0 ? ((vids) * 5) + 245 : 0) #define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 @@ -4251,6 +4308,15 @@ #define GEN7_L3LOG_BASE 0xB070 #define GEN7_L3LOG_SIZE 0x80 +#define GEN7_HALF_SLICE_CHICKEN1 0xe100 /* IVB GT1 + VLV */ +#define GEN7_HALF_SLICE_CHICKEN1_GT2 0xf100 +#define GEN7_MAX_PS_THREAD_DEP (8<<12) +#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3) + +#define GEN7_ROW_CHICKEN2 0xe4f4 +#define GEN7_ROW_CHICKEN2_GT2 0xf4f4 +#define DOP_CLOCK_GATING_DISABLE (1<<0) + #define G4X_AUD_VID_DID 0x62020 #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 @@ -4380,33 +4446,39 @@ #define HSW_PWR_WELL_CTL6 0x45414 /* Per-pipe DDI Function Control */ -#define PIPE_DDI_FUNC_CTL_A 0x60400 -#define PIPE_DDI_FUNC_CTL_B 0x61400 -#define PIPE_DDI_FUNC_CTL_C 0x62400 -#define PIPE_DDI_FUNC_CTL_EDP 0x6F400 -#define DDI_FUNC_CTL(pipe) _PIPE(pipe, PIPE_DDI_FUNC_CTL_A, \ - PIPE_DDI_FUNC_CTL_B) -#define PIPE_DDI_FUNC_ENABLE (1<<31) +#define TRANS_DDI_FUNC_CTL_A 0x60400 +#define TRANS_DDI_FUNC_CTL_B 0x61400 +#define TRANS_DDI_FUNC_CTL_C 0x62400 +#define TRANS_DDI_FUNC_CTL_EDP 0x6F400 +#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER(tran, TRANS_DDI_FUNC_CTL_A, \ + TRANS_DDI_FUNC_CTL_B) +#define TRANS_DDI_FUNC_ENABLE (1<<31) /* Those bits are ignored by pipe EDP since it can only connect to DDI A */ -#define PIPE_DDI_PORT_MASK (7<<28) -#define PIPE_DDI_SELECT_PORT(x) ((x)<<28) -#define PIPE_DDI_MODE_SELECT_MASK (7<<24) -#define PIPE_DDI_MODE_SELECT_HDMI (0<<24) -#define PIPE_DDI_MODE_SELECT_DVI (1<<24) -#define PIPE_DDI_MODE_SELECT_DP_SST (2<<24) -#define PIPE_DDI_MODE_SELECT_DP_MST (3<<24) -#define PIPE_DDI_MODE_SELECT_FDI (4<<24) -#define PIPE_DDI_BPC_MASK (7<<20) -#define PIPE_DDI_BPC_8 (0<<20) -#define PIPE_DDI_BPC_10 (1<<20) -#define PIPE_DDI_BPC_6 (2<<20) -#define PIPE_DDI_BPC_12 (3<<20) -#define PIPE_DDI_PVSYNC (1<<17) -#define PIPE_DDI_PHSYNC (1<<16) -#define PIPE_DDI_BFI_ENABLE (1<<4) -#define PIPE_DDI_PORT_WIDTH_X1 (0<<1) -#define PIPE_DDI_PORT_WIDTH_X2 (1<<1) -#define PIPE_DDI_PORT_WIDTH_X4 (3<<1) +#define TRANS_DDI_PORT_MASK (7<<28) +#define TRANS_DDI_SELECT_PORT(x) ((x)<<28) +#define TRANS_DDI_PORT_NONE (0<<28) +#define TRANS_DDI_MODE_SELECT_MASK (7<<24) +#define TRANS_DDI_MODE_SELECT_HDMI (0<<24) +#define TRANS_DDI_MODE_SELECT_DVI (1<<24) +#define TRANS_DDI_MODE_SELECT_DP_SST (2<<24) +#define TRANS_DDI_MODE_SELECT_DP_MST (3<<24) +#define TRANS_DDI_MODE_SELECT_FDI (4<<24) +#define TRANS_DDI_BPC_MASK (7<<20) +#define TRANS_DDI_BPC_8 (0<<20) +#define TRANS_DDI_BPC_10 (1<<20) +#define TRANS_DDI_BPC_6 (2<<20) +#define TRANS_DDI_BPC_12 (3<<20) +#define TRANS_DDI_PVSYNC (1<<17) +#define TRANS_DDI_PHSYNC (1<<16) +#define TRANS_DDI_EDP_INPUT_MASK (7<<12) +#define TRANS_DDI_EDP_INPUT_A_ON (0<<12) +#define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12) +#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12) +#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) +#define TRANS_DDI_BFI_ENABLE (1<<4) +#define TRANS_DDI_PORT_WIDTH_X1 (0<<1) +#define TRANS_DDI_PORT_WIDTH_X2 (1<<1) +#define TRANS_DDI_PORT_WIDTH_X4 (3<<1) /* DisplayPort Transport Control */ #define DP_TP_CTL_A 0x64040 @@ -4420,12 +4492,16 @@ #define DP_TP_CTL_LINK_TRAIN_MASK (7<<8) #define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8) #define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT3 (4<<8) +#define DP_TP_CTL_LINK_TRAIN_IDLE (2<<8) #define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8) +#define DP_TP_CTL_SCRAMBLE_DISABLE (1<<7) /* DisplayPort Transport Status */ #define DP_TP_STATUS_A 0x64044 #define DP_TP_STATUS_B 0x64144 #define DP_TP_STATUS(port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B) +#define DP_TP_STATUS_IDLE_DONE (1<<25) #define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) /* DDI Buffer Control */ @@ -4444,6 +4520,7 @@ #define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */ #define DDI_BUF_EMP_MASK (0xf<<24) #define DDI_BUF_IS_IDLE (1<<7) +#define DDI_A_4_LANES (1<<4) #define DDI_PORT_WIDTH_X1 (0<<1) #define DDI_PORT_WIDTH_X2 (1<<1) #define DDI_PORT_WIDTH_X4 (3<<1) @@ -4460,6 +4537,10 @@ #define SBI_ADDR 0xC6000 #define SBI_DATA 0xC6004 #define SBI_CTL_STAT 0xC6008 +#define SBI_CTL_DEST_ICLK (0x0<<16) +#define SBI_CTL_DEST_MPHY (0x1<<16) +#define SBI_CTL_OP_IORD (0x2<<8) +#define SBI_CTL_OP_IOWR (0x3<<8) #define SBI_CTL_OP_CRRD (0x6<<8) #define SBI_CTL_OP_CRWR (0x7<<8) #define SBI_RESPONSE_FAIL (0x1<<1) @@ -4477,10 +4558,12 @@ #define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0) #define SBI_SSCCTL 0x020c #define SBI_SSCCTL6 0x060C +#define SBI_SSCCTL_PATHALT (1<<3) #define SBI_SSCCTL_DISABLE (1<<0) #define SBI_SSCAUXDIV6 0x0610 #define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4) #define SBI_DBUFF0 0x2a00 +#define SBI_DBUFF0_ENABLE (1<<0) /* LPT PIXCLK_GATE */ #define PIXCLK_GATE 0xC6020 @@ -4490,8 +4573,8 @@ /* SPLL */ #define SPLL_CTL 0x46020 #define SPLL_PLL_ENABLE (1<<31) -#define SPLL_PLL_SCC (1<<28) -#define SPLL_PLL_NON_SCC (2<<28) +#define SPLL_PLL_SSC (1<<28) +#define SPLL_PLL_NON_SSC (2<<28) #define SPLL_PLL_FREQ_810MHz (0<<26) #define SPLL_PLL_FREQ_1350MHz (1<<26) @@ -4500,7 +4583,7 @@ #define WRPLL_CTL2 0x46060 #define WRPLL_PLL_ENABLE (1<<31) #define WRPLL_PLL_SELECT_SSC (0x01<<28) -#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28) +#define WRPLL_PLL_SELECT_NON_SSC (0x02<<28) #define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) /* WRPLL divider programming */ #define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) @@ -4517,21 +4600,36 @@ #define PORT_CLK_SEL_SPLL (3<<29) #define PORT_CLK_SEL_WRPLL1 (4<<29) #define PORT_CLK_SEL_WRPLL2 (5<<29) - -/* Pipe clock selection */ -#define PIPE_CLK_SEL_A 0x46140 -#define PIPE_CLK_SEL_B 0x46144 -#define PIPE_CLK_SEL(pipe) _PIPE(pipe, PIPE_CLK_SEL_A, PIPE_CLK_SEL_B) -/* For each pipe, we need to select the corresponding port clock */ -#define PIPE_CLK_SEL_DISABLED (0x0<<29) -#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29) +#define PORT_CLK_SEL_NONE (7<<29) + +/* Transcoder clock selection */ +#define TRANS_CLK_SEL_A 0x46140 +#define TRANS_CLK_SEL_B 0x46144 +#define TRANS_CLK_SEL(tran) _TRANSCODER(tran, TRANS_CLK_SEL_A, TRANS_CLK_SEL_B) +/* For each transcoder, we need to select the corresponding port clock */ +#define TRANS_CLK_SEL_DISABLED (0x0<<29) +#define TRANS_CLK_SEL_PORT(x) ((x+1)<<29) + +#define _TRANSA_MSA_MISC 0x60410 +#define _TRANSB_MSA_MISC 0x61410 +#define TRANS_MSA_MISC(tran) _TRANSCODER(tran, _TRANSA_MSA_MISC, \ + _TRANSB_MSA_MISC) +#define TRANS_MSA_SYNC_CLK (1<<0) +#define TRANS_MSA_6_BPC (0<<5) +#define TRANS_MSA_8_BPC (1<<5) +#define TRANS_MSA_10_BPC (2<<5) +#define TRANS_MSA_12_BPC (3<<5) +#define TRANS_MSA_16_BPC (4<<5) /* LCPLL Control */ #define LCPLL_CTL 0x130040 #define LCPLL_PLL_DISABLE (1<<31) #define LCPLL_PLL_LOCK (1<<30) +#define LCPLL_CLK_FREQ_MASK (3<<26) +#define LCPLL_CLK_FREQ_450 (0<<26) #define LCPLL_CD_CLOCK_DISABLE (1<<25) #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) +#define LCPLL_CD_SOURCE_FCLK (1<<21) /* Pipe WM_LINETIME - watermark line time */ #define PIPE_WM_LINETIME_A 0x45270 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 5854bdd..63d4d30 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -60,9 +60,9 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe) reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; if (pipe == PIPE_A) - array = dev_priv->save_palette_a; + array = dev_priv->regfile.save_palette_a; else - array = dev_priv->save_palette_b; + array = dev_priv->regfile.save_palette_b; for (i = 0; i < 256; i++) array[i] = I915_READ(reg + (i << 2)); @@ -82,9 +82,9 @@ static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; if (pipe == PIPE_A) - array = dev_priv->save_palette_a; + array = dev_priv->regfile.save_palette_a; else - array = dev_priv->save_palette_b; + array = dev_priv->regfile.save_palette_b; for (i = 0; i < 256; i++) I915_WRITE(reg + (i << 2), array[i]); @@ -131,11 +131,11 @@ static void i915_save_vga(struct drm_device *dev) u16 cr_index, cr_data, st01; /* VGA color palette registers */ - dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK); + dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK); /* MSR bits */ - dev_priv->saveMSR = I915_READ8(VGA_MSR_READ); - if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + dev_priv->regfile.saveMSR = I915_READ8(VGA_MSR_READ); + if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { cr_index = VGA_CR_INDEX_CGA; cr_data = VGA_CR_DATA_CGA; st01 = VGA_ST01_CGA; @@ -150,35 +150,35 @@ static void i915_save_vga(struct drm_device *dev) i915_read_indexed(dev, cr_index, cr_data, 0x11) & (~0x80)); for (i = 0; i <= 0x24; i++) - dev_priv->saveCR[i] = + dev_priv->regfile.saveCR[i] = i915_read_indexed(dev, cr_index, cr_data, i); /* Make sure we don't turn off CR group 0 writes */ - dev_priv->saveCR[0x11] &= ~0x80; + dev_priv->regfile.saveCR[0x11] &= ~0x80; /* Attribute controller registers */ I915_READ8(st01); - dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX); + dev_priv->regfile.saveAR_INDEX = I915_READ8(VGA_AR_INDEX); for (i = 0; i <= 0x14; i++) - dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0); + dev_priv->regfile.saveAR[i] = i915_read_ar(dev, st01, i, 0); I915_READ8(st01); - I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX); + I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX); I915_READ8(st01); /* Graphics controller registers */ for (i = 0; i < 9; i++) - dev_priv->saveGR[i] = + dev_priv->regfile.saveGR[i] = i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i); - dev_priv->saveGR[0x10] = + dev_priv->regfile.saveGR[0x10] = i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10); - dev_priv->saveGR[0x11] = + dev_priv->regfile.saveGR[0x11] = i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11); - dev_priv->saveGR[0x18] = + dev_priv->regfile.saveGR[0x18] = i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18); /* Sequencer registers */ for (i = 0; i < 8; i++) - dev_priv->saveSR[i] = + dev_priv->regfile.saveSR[i] = i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i); } @@ -189,8 +189,8 @@ static void i915_restore_vga(struct drm_device *dev) u16 cr_index, cr_data, st01; /* MSR bits */ - I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR); - if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR); + if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { cr_index = VGA_CR_INDEX_CGA; cr_data = VGA_CR_DATA_CGA; st01 = VGA_ST01_CGA; @@ -203,36 +203,36 @@ static void i915_restore_vga(struct drm_device *dev) /* Sequencer registers, don't write SR07 */ for (i = 0; i < 7; i++) i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i, - dev_priv->saveSR[i]); + dev_priv->regfile.saveSR[i]); /* CRT controller regs */ /* Enable CR group 0 writes */ - i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); + i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->regfile.saveCR[0x11]); for (i = 0; i <= 0x24; i++) - i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]); + i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->regfile.saveCR[i]); /* Graphics controller regs */ for (i = 0; i < 9; i++) i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i, - dev_priv->saveGR[i]); + dev_priv->regfile.saveGR[i]); i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10, - dev_priv->saveGR[0x10]); + dev_priv->regfile.saveGR[0x10]); i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11, - dev_priv->saveGR[0x11]); + dev_priv->regfile.saveGR[0x11]); i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18, - dev_priv->saveGR[0x18]); + dev_priv->regfile.saveGR[0x18]); /* Attribute controller registers */ I915_READ8(st01); /* switch back to index mode */ for (i = 0; i <= 0x14; i++) - i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0); + i915_write_ar(dev, st01, i, dev_priv->regfile.saveAR[i], 0); I915_READ8(st01); /* switch back to index mode */ - I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20); + I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX | 0x20); I915_READ8(st01); /* VGA color palette registers */ - I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK); + I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK); } static void i915_save_modeset_reg(struct drm_device *dev) @@ -244,156 +244,162 @@ static void i915_save_modeset_reg(struct drm_device *dev) return; /* Cursor state */ - dev_priv->saveCURACNTR = I915_READ(_CURACNTR); - dev_priv->saveCURAPOS = I915_READ(_CURAPOS); - dev_priv->saveCURABASE = I915_READ(_CURABASE); - dev_priv->saveCURBCNTR = I915_READ(_CURBCNTR); - dev_priv->saveCURBPOS = I915_READ(_CURBPOS); - dev_priv->saveCURBBASE = I915_READ(_CURBBASE); + dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR); + dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS); + dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE); + dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR); + dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS); + dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE); if (IS_GEN2(dev)) - dev_priv->saveCURSIZE = I915_READ(CURSIZE); + dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE); if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); - dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); + dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); + dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); } /* Pipe & plane A info */ - dev_priv->savePIPEACONF = I915_READ(_PIPEACONF); - dev_priv->savePIPEASRC = I915_READ(_PIPEASRC); + dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF); + dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC); if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveFPA0 = I915_READ(_PCH_FPA0); - dev_priv->saveFPA1 = I915_READ(_PCH_FPA1); - dev_priv->saveDPLL_A = I915_READ(_PCH_DPLL_A); + dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0); + dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1); + dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A); } else { - dev_priv->saveFPA0 = I915_READ(_FPA0); - dev_priv->saveFPA1 = I915_READ(_FPA1); - dev_priv->saveDPLL_A = I915_READ(_DPLL_A); + dev_priv->regfile.saveFPA0 = I915_READ(_FPA0); + dev_priv->regfile.saveFPA1 = I915_READ(_FPA1); + dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A); } if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->saveDPLL_A_MD = I915_READ(_DPLL_A_MD); - dev_priv->saveHTOTAL_A = I915_READ(_HTOTAL_A); - dev_priv->saveHBLANK_A = I915_READ(_HBLANK_A); - dev_priv->saveHSYNC_A = I915_READ(_HSYNC_A); - dev_priv->saveVTOTAL_A = I915_READ(_VTOTAL_A); - dev_priv->saveVBLANK_A = I915_READ(_VBLANK_A); - dev_priv->saveVSYNC_A = I915_READ(_VSYNC_A); + dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD); + dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A); + dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A); + dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A); + dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A); + dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A); + dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A); if (!HAS_PCH_SPLIT(dev)) - dev_priv->saveBCLRPAT_A = I915_READ(_BCLRPAT_A); + dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A); if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1); - dev_priv->savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1); - dev_priv->savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1); - dev_priv->savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1); - - dev_priv->saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL); - dev_priv->saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL); - - dev_priv->savePFA_CTL_1 = I915_READ(_PFA_CTL_1); - dev_priv->savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); - dev_priv->savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); - - dev_priv->saveTRANSACONF = I915_READ(_TRANSACONF); - dev_priv->saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); - dev_priv->saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); - dev_priv->saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); - dev_priv->saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); - dev_priv->saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); - dev_priv->saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); - } - - dev_priv->saveDSPACNTR = I915_READ(_DSPACNTR); - dev_priv->saveDSPASTRIDE = I915_READ(_DSPASTRIDE); - dev_priv->saveDSPASIZE = I915_READ(_DSPASIZE); - dev_priv->saveDSPAPOS = I915_READ(_DSPAPOS); - dev_priv->saveDSPAADDR = I915_READ(_DSPAADDR); + dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1); + dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1); + dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1); + dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1); + + dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL); + dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL); + + dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1); + dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); + dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); + + dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF); + dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); + dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); + dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); + dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); + dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); + dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); + } + + dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR); + dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE); + dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE); + dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS); + dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR); if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->saveDSPASURF = I915_READ(_DSPASURF); - dev_priv->saveDSPATILEOFF = I915_READ(_DSPATILEOFF); + dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF); + dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF); } i915_save_palette(dev, PIPE_A); - dev_priv->savePIPEASTAT = I915_READ(_PIPEASTAT); + dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT); /* Pipe & plane B info */ - dev_priv->savePIPEBCONF = I915_READ(_PIPEBCONF); - dev_priv->savePIPEBSRC = I915_READ(_PIPEBSRC); + dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF); + dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC); if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveFPB0 = I915_READ(_PCH_FPB0); - dev_priv->saveFPB1 = I915_READ(_PCH_FPB1); - dev_priv->saveDPLL_B = I915_READ(_PCH_DPLL_B); + dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0); + dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1); + dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B); } else { - dev_priv->saveFPB0 = I915_READ(_FPB0); - dev_priv->saveFPB1 = I915_READ(_FPB1); - dev_priv->saveDPLL_B = I915_READ(_DPLL_B); + dev_priv->regfile.saveFPB0 = I915_READ(_FPB0); + dev_priv->regfile.saveFPB1 = I915_READ(_FPB1); + dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B); } if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->saveDPLL_B_MD = I915_READ(_DPLL_B_MD); - dev_priv->saveHTOTAL_B = I915_READ(_HTOTAL_B); - dev_priv->saveHBLANK_B = I915_READ(_HBLANK_B); - dev_priv->saveHSYNC_B = I915_READ(_HSYNC_B); - dev_priv->saveVTOTAL_B = I915_READ(_VTOTAL_B); - dev_priv->saveVBLANK_B = I915_READ(_VBLANK_B); - dev_priv->saveVSYNC_B = I915_READ(_VSYNC_B); + dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD); + dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B); + dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B); + dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B); + dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B); + dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B); + dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B); if (!HAS_PCH_SPLIT(dev)) - dev_priv->saveBCLRPAT_B = I915_READ(_BCLRPAT_B); + dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B); if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1); - dev_priv->savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1); - dev_priv->savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1); - dev_priv->savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1); - - dev_priv->saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL); - dev_priv->saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL); - - dev_priv->savePFB_CTL_1 = I915_READ(_PFB_CTL_1); - dev_priv->savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); - dev_priv->savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); - - dev_priv->saveTRANSBCONF = I915_READ(_TRANSBCONF); - dev_priv->saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); - dev_priv->saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); - dev_priv->saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); - dev_priv->saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); - dev_priv->saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); - dev_priv->saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); - } - - dev_priv->saveDSPBCNTR = I915_READ(_DSPBCNTR); - dev_priv->saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE); - dev_priv->saveDSPBSIZE = I915_READ(_DSPBSIZE); - dev_priv->saveDSPBPOS = I915_READ(_DSPBPOS); - dev_priv->saveDSPBADDR = I915_READ(_DSPBADDR); + dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1); + dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1); + dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1); + dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1); + + dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL); + dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL); + + dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1); + dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); + dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); + + dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF); + dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); + dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); + dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); + dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); + dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); + dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); + } + + dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR); + dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE); + dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE); + dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS); + dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR); if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->saveDSPBSURF = I915_READ(_DSPBSURF); - dev_priv->saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF); + dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF); + dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); - dev_priv->savePIPEBSTAT = I915_READ(_PIPEBSTAT); + dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT); /* Fences */ switch (INTEL_INFO(dev)->gen) { case 7: case 6: for (i = 0; i < 16; i++) - dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); + dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); break; case 5: case 4: for (i = 0; i < 16; i++) - dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); + dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); break; case 3: if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) for (i = 0; i < 8; i++) - dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); + dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); case 2: for (i = 0; i < 8; i++) - dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); + dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); break; } + /* CRT state */ + if (HAS_PCH_SPLIT(dev)) + dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA); + else + dev_priv->regfile.saveADPA = I915_READ(ADPA); + return; } @@ -412,20 +418,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) case 7: case 6: for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]); + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); break; case 5: case 4: for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]); + I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); break; case 3: case 2: if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]); + I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]); for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]); + I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]); break; } @@ -447,158 +453,164 @@ static void i915_restore_modeset_reg(struct drm_device *dev) } if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL); - I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL); + I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL); + I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL); } /* Pipe & plane A info */ /* Prime the clock */ - if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { - I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A & + if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A & ~DPLL_VCO_ENABLE); POSTING_READ(dpll_a_reg); udelay(150); } - I915_WRITE(fpa0_reg, dev_priv->saveFPA0); - I915_WRITE(fpa1_reg, dev_priv->saveFPA1); + I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0); + I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1); /* Actually enable it */ - I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); + I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A); POSTING_READ(dpll_a_reg); udelay(150); if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(_DPLL_A_MD, dev_priv->saveDPLL_A_MD); + I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD); POSTING_READ(_DPLL_A_MD); } udelay(150); /* Restore mode */ - I915_WRITE(_HTOTAL_A, dev_priv->saveHTOTAL_A); - I915_WRITE(_HBLANK_A, dev_priv->saveHBLANK_A); - I915_WRITE(_HSYNC_A, dev_priv->saveHSYNC_A); - I915_WRITE(_VTOTAL_A, dev_priv->saveVTOTAL_A); - I915_WRITE(_VBLANK_A, dev_priv->saveVBLANK_A); - I915_WRITE(_VSYNC_A, dev_priv->saveVSYNC_A); + I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A); + I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A); + I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A); + I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A); + I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A); + I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A); if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(_BCLRPAT_A, dev_priv->saveBCLRPAT_A); + I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(_PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); - I915_WRITE(_PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); - I915_WRITE(_PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); - I915_WRITE(_PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1); + I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1); + I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1); + I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1); + I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1); - I915_WRITE(_FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL); - I915_WRITE(_FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL); + I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL); + I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL); - I915_WRITE(_PFA_CTL_1, dev_priv->savePFA_CTL_1); - I915_WRITE(_PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ); - I915_WRITE(_PFA_WIN_POS, dev_priv->savePFA_WIN_POS); + I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1); + I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ); + I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS); - I915_WRITE(_TRANSACONF, dev_priv->saveTRANSACONF); - I915_WRITE(_TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A); - I915_WRITE(_TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A); - I915_WRITE(_TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A); - I915_WRITE(_TRANS_VTOTAL_A, dev_priv->saveTRANS_VTOTAL_A); - I915_WRITE(_TRANS_VBLANK_A, dev_priv->saveTRANS_VBLANK_A); - I915_WRITE(_TRANS_VSYNC_A, dev_priv->saveTRANS_VSYNC_A); + I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF); + I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); + I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); + I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); + I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A); + I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A); + I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A); } /* Restore plane info */ - I915_WRITE(_DSPASIZE, dev_priv->saveDSPASIZE); - I915_WRITE(_DSPAPOS, dev_priv->saveDSPAPOS); - I915_WRITE(_PIPEASRC, dev_priv->savePIPEASRC); - I915_WRITE(_DSPAADDR, dev_priv->saveDSPAADDR); - I915_WRITE(_DSPASTRIDE, dev_priv->saveDSPASTRIDE); + I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE); + I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS); + I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC); + I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR); + I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE); if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(_DSPASURF, dev_priv->saveDSPASURF); - I915_WRITE(_DSPATILEOFF, dev_priv->saveDSPATILEOFF); + I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF); + I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF); } - I915_WRITE(_PIPEACONF, dev_priv->savePIPEACONF); + I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF); i915_restore_palette(dev, PIPE_A); /* Enable the plane */ - I915_WRITE(_DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR); I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR)); /* Pipe & plane B info */ - if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { - I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B & + if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B & ~DPLL_VCO_ENABLE); POSTING_READ(dpll_b_reg); udelay(150); } - I915_WRITE(fpb0_reg, dev_priv->saveFPB0); - I915_WRITE(fpb1_reg, dev_priv->saveFPB1); + I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0); + I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1); /* Actually enable it */ - I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); + I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B); POSTING_READ(dpll_b_reg); udelay(150); if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(_DPLL_B_MD, dev_priv->saveDPLL_B_MD); + I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD); POSTING_READ(_DPLL_B_MD); } udelay(150); /* Restore mode */ - I915_WRITE(_HTOTAL_B, dev_priv->saveHTOTAL_B); - I915_WRITE(_HBLANK_B, dev_priv->saveHBLANK_B); - I915_WRITE(_HSYNC_B, dev_priv->saveHSYNC_B); - I915_WRITE(_VTOTAL_B, dev_priv->saveVTOTAL_B); - I915_WRITE(_VBLANK_B, dev_priv->saveVBLANK_B); - I915_WRITE(_VSYNC_B, dev_priv->saveVSYNC_B); + I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B); + I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B); + I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B); + I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B); + I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B); + I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B); if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(_BCLRPAT_B, dev_priv->saveBCLRPAT_B); + I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(_PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); - I915_WRITE(_PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); - I915_WRITE(_PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); - I915_WRITE(_PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1); + I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1); + I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1); + I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1); + I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1); - I915_WRITE(_FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL); - I915_WRITE(_FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL); + I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL); + I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL); - I915_WRITE(_PFB_CTL_1, dev_priv->savePFB_CTL_1); - I915_WRITE(_PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ); - I915_WRITE(_PFB_WIN_POS, dev_priv->savePFB_WIN_POS); + I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1); + I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ); + I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS); - I915_WRITE(_TRANSBCONF, dev_priv->saveTRANSBCONF); - I915_WRITE(_TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B); - I915_WRITE(_TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B); - I915_WRITE(_TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B); - I915_WRITE(_TRANS_VTOTAL_B, dev_priv->saveTRANS_VTOTAL_B); - I915_WRITE(_TRANS_VBLANK_B, dev_priv->saveTRANS_VBLANK_B); - I915_WRITE(_TRANS_VSYNC_B, dev_priv->saveTRANS_VSYNC_B); + I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); + I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); + I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); + I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); + I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B); + I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B); + I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B); } /* Restore plane info */ - I915_WRITE(_DSPBSIZE, dev_priv->saveDSPBSIZE); - I915_WRITE(_DSPBPOS, dev_priv->saveDSPBPOS); - I915_WRITE(_PIPEBSRC, dev_priv->savePIPEBSRC); - I915_WRITE(_DSPBADDR, dev_priv->saveDSPBADDR); - I915_WRITE(_DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE); + I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS); + I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC); + I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR); + I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE); if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(_DSPBSURF, dev_priv->saveDSPBSURF); - I915_WRITE(_DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); + I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF); + I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF); } - I915_WRITE(_PIPEBCONF, dev_priv->savePIPEBCONF); + I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF); i915_restore_palette(dev, PIPE_B); /* Enable the plane */ - I915_WRITE(_DSPBCNTR, dev_priv->saveDSPBCNTR); + I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR); I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR)); /* Cursor state */ - I915_WRITE(_CURAPOS, dev_priv->saveCURAPOS); - I915_WRITE(_CURACNTR, dev_priv->saveCURACNTR); - I915_WRITE(_CURABASE, dev_priv->saveCURABASE); - I915_WRITE(_CURBPOS, dev_priv->saveCURBPOS); - I915_WRITE(_CURBCNTR, dev_priv->saveCURBCNTR); - I915_WRITE(_CURBBASE, dev_priv->saveCURBBASE); + I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS); + I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR); + I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE); + I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS); + I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR); + I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE); if (IS_GEN2(dev)) - I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); + I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE); + + /* CRT state */ + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA); + else + I915_WRITE(ADPA, dev_priv->regfile.saveADPA); return; } @@ -608,89 +620,84 @@ static void i915_save_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Display arbitration control */ - dev_priv->saveDSPARB = I915_READ(DSPARB); + dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); /* This is only meaningful in non-KMS mode */ - /* Don't save them in KMS mode */ + /* Don't regfile.save them in KMS mode */ i915_save_modeset_reg(dev); - /* CRT state */ - if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveADPA = I915_READ(PCH_ADPA); - } else { - dev_priv->saveADPA = I915_READ(ADPA); - } - /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL); - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); - dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); - dev_priv->saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); - dev_priv->saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); - dev_priv->saveLVDS = I915_READ(PCH_LVDS); + dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); + dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); + dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); + dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); + dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); } else { - dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); - dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); - dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); + dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); + dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); + dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); if (INTEL_INFO(dev)->gen >= 4) - dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); if (IS_MOBILE(dev) && !IS_I830(dev)) - dev_priv->saveLVDS = I915_READ(LVDS); + dev_priv->regfile.saveLVDS = I915_READ(LVDS); } if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) - dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); + dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); - dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); - dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); + dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); + dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); + dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); } else { - dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); - dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); - dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); - } - - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - dev_priv->saveDP_B = I915_READ(DP_B); - dev_priv->saveDP_C = I915_READ(DP_C); - dev_priv->saveDP_D = I915_READ(DP_D); - dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); - dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); - dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); - dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); - dev_priv->savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); - dev_priv->savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); - dev_priv->savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); - dev_priv->savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); - } - /* FIXME: save TV & SDVO state */ - - /* Only save FBC state on the platform that supports FBC */ + dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); + dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); + dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR); + } + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + dev_priv->regfile.saveDP_B = I915_READ(DP_B); + dev_priv->regfile.saveDP_C = I915_READ(DP_C); + dev_priv->regfile.saveDP_D = I915_READ(DP_D); + dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); + dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); + dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); + dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); + dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); + dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); + dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); + dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); + } + /* FIXME: regfile.save TV & SDVO state */ + } + + /* Only regfile.save FBC state on the platform that supports FBC */ if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); + dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); } else if (IS_GM45(dev)) { - dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); + dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); } else { - dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); - dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); - dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); - dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + dev_priv->regfile.saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); + dev_priv->regfile.saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); + dev_priv->regfile.saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); + dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL); } } /* VGA state */ - dev_priv->saveVGA0 = I915_READ(VGA0); - dev_priv->saveVGA1 = I915_READ(VGA1); - dev_priv->saveVGA_PD = I915_READ(VGA_PD); + dev_priv->regfile.saveVGA0 = I915_READ(VGA0); + dev_priv->regfile.saveVGA1 = I915_READ(VGA1); + dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); if (HAS_PCH_SPLIT(dev)) - dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL); + dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL); else - dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL); i915_save_vga(dev); } @@ -700,97 +707,95 @@ static void i915_restore_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Display arbitration */ - I915_WRITE(DSPARB, dev_priv->saveDSPARB); - - /* Display port ratios (must be done before clock is set) */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M); - I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M); - I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N); - I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N); - I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M); - I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M); - I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N); - I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N); + I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Display port ratios (must be done before clock is set) */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); + I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); + I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); + I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); + I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); + I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); + I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); + I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); + } } /* This is only meaningful in non-KMS mode */ /* Don't restore them in KMS mode */ i915_restore_modeset_reg(dev); - /* CRT state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(PCH_ADPA, dev_priv->saveADPA); - else - I915_WRITE(ADPA, dev_priv->saveADPA); - /* LVDS state */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); + I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_LVDS, dev_priv->saveLVDS); + I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS); } else if (IS_MOBILE(dev) && !IS_I830(dev)) - I915_WRITE(LVDS, dev_priv->saveLVDS); + I915_WRITE(LVDS, dev_priv->regfile.saveLVDS); if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) - I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); + I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2); + I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); + I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; * otherwise we get blank eDP screen after S3 on some machines */ - I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->saveBLC_CPU_PWM_CTL2); - I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL); - I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS); - I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); - I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR); - I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL); + I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2); + I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL); + I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); + I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); + I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); + I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL); I915_WRITE(RSTDBYCTL, - dev_priv->saveMCHBAR_RENDER_STANDBY); + dev_priv->regfile.saveMCHBAR_RENDER_STANDBY); } else { - I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); - I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(BLC_HIST_CTL, dev_priv->saveBLC_HIST_CTL); - I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS); - I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); - I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); - I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); - } - - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(DP_B, dev_priv->saveDP_B); - I915_WRITE(DP_C, dev_priv->saveDP_C); - I915_WRITE(DP_D, dev_priv->saveDP_D); + I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS); + I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL); + I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL); + I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); + I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); + I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); + I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); + } + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(DP_B, dev_priv->regfile.saveDP_B); + I915_WRITE(DP_C, dev_priv->regfile.saveDP_C); + I915_WRITE(DP_D, dev_priv->regfile.saveDP_D); + } + /* FIXME: restore TV & SDVO state */ } - /* FIXME: restore TV & SDVO state */ /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); + I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); } else if (IS_GM45(dev)) { - I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); + I915_WRITE(DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); } else { - I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); - I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); - I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); - I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL); + I915_WRITE(FBC_CFB_BASE, dev_priv->regfile.saveFBC_CFB_BASE); + I915_WRITE(FBC_LL_BASE, dev_priv->regfile.saveFBC_LL_BASE); + I915_WRITE(FBC_CONTROL2, dev_priv->regfile.saveFBC_CONTROL2); + I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); } } /* VGA state */ if (HAS_PCH_SPLIT(dev)) - I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL); + I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL); else - I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); + I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL); - I915_WRITE(VGA0, dev_priv->saveVGA0); - I915_WRITE(VGA1, dev_priv->saveVGA1); - I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); + I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); + I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); + I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); POSTING_READ(VGA_PD); udelay(150); @@ -802,46 +807,45 @@ int i915_save_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + pci_read_config_byte(dev->pdev, LBB, &dev_priv->regfile.saveLBB); mutex_lock(&dev->struct_mutex); - /* Hardware status page */ - dev_priv->saveHWS = I915_READ(HWS_PGA); - i915_save_display(dev); - /* Interrupt state */ - if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveDEIER = I915_READ(DEIER); - dev_priv->saveDEIMR = I915_READ(DEIMR); - dev_priv->saveGTIER = I915_READ(GTIER); - dev_priv->saveGTIMR = I915_READ(GTIMR); - dev_priv->saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR); - dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); - dev_priv->saveMCHBAR_RENDER_STANDBY = - I915_READ(RSTDBYCTL); - dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); - } else { - dev_priv->saveIER = I915_READ(IER); - dev_priv->saveIMR = I915_READ(IMR); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Interrupt state */ + if (HAS_PCH_SPLIT(dev)) { + dev_priv->regfile.saveDEIER = I915_READ(DEIER); + dev_priv->regfile.saveDEIMR = I915_READ(DEIMR); + dev_priv->regfile.saveGTIER = I915_READ(GTIER); + dev_priv->regfile.saveGTIMR = I915_READ(GTIMR); + dev_priv->regfile.saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR); + dev_priv->regfile.saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); + dev_priv->regfile.saveMCHBAR_RENDER_STANDBY = + I915_READ(RSTDBYCTL); + dev_priv->regfile.savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); + } else { + dev_priv->regfile.saveIER = I915_READ(IER); + dev_priv->regfile.saveIMR = I915_READ(IMR); + } } intel_disable_gt_powersave(dev); /* Cache mode state */ - dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + dev_priv->regfile.saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); /* Memory Arbitration state */ - dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); + dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); /* Scratch space */ for (i = 0; i < 16; i++) { - dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2)); - dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); + dev_priv->regfile.saveSWF0[i] = I915_READ(SWF00 + (i << 2)); + dev_priv->regfile.saveSWF1[i] = I915_READ(SWF10 + (i << 2)); } for (i = 0; i < 3; i++) - dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); + dev_priv->regfile.saveSWF2[i] = I915_READ(SWF30 + (i << 2)); mutex_unlock(&dev->struct_mutex); @@ -853,41 +857,40 @@ int i915_restore_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + pci_write_config_byte(dev->pdev, LBB, dev_priv->regfile.saveLBB); mutex_lock(&dev->struct_mutex); - /* Hardware status page */ - I915_WRITE(HWS_PGA, dev_priv->saveHWS); - i915_restore_display(dev); - /* Interrupt state */ - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(DEIER, dev_priv->saveDEIER); - I915_WRITE(DEIMR, dev_priv->saveDEIMR); - I915_WRITE(GTIER, dev_priv->saveGTIER); - I915_WRITE(GTIMR, dev_priv->saveGTIMR); - I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); - I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); - I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG); - } else { - I915_WRITE(IER, dev_priv->saveIER); - I915_WRITE(IMR, dev_priv->saveIMR); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Interrupt state */ + if (HAS_PCH_SPLIT(dev)) { + I915_WRITE(DEIER, dev_priv->regfile.saveDEIER); + I915_WRITE(DEIMR, dev_priv->regfile.saveDEIMR); + I915_WRITE(GTIER, dev_priv->regfile.saveGTIER); + I915_WRITE(GTIMR, dev_priv->regfile.saveGTIMR); + I915_WRITE(_FDI_RXA_IMR, dev_priv->regfile.saveFDI_RXA_IMR); + I915_WRITE(_FDI_RXB_IMR, dev_priv->regfile.saveFDI_RXB_IMR); + I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->regfile.savePCH_PORT_HOTPLUG); + } else { + I915_WRITE(IER, dev_priv->regfile.saveIER); + I915_WRITE(IMR, dev_priv->regfile.saveIMR); + } } /* Cache mode state */ - I915_WRITE(CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); + I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 | 0xffff0000); /* Memory arbitration state */ - I915_WRITE(MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); + I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000); for (i = 0; i < 16; i++) { - I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]); - I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]); + I915_WRITE(SWF00 + (i << 2), dev_priv->regfile.saveSWF0[i]); + I915_WRITE(SWF10 + (i << 2), dev_priv->regfile.saveSWF1[i]); } for (i = 0; i < 3; i++) - I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); + I915_WRITE(SWF30 + (i << 2), dev_priv->regfile.saveSWF2[i]); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 903eebd..9462081 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -97,7 +97,7 @@ static struct attribute_group rc6_attr_group = { static int l3_access_valid(struct drm_device *dev, loff_t offset) { - if (!IS_IVYBRIDGE(dev)) + if (!HAS_L3_GPU_CACHE(dev)) return -EPERM; if (offset % 4 != 0) @@ -162,7 +162,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj, if (ret) return ret; - if (!dev_priv->mm.l3_remap_info) { + if (!dev_priv->l3_parity.remap_info) { temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL); if (!temp) { mutex_unlock(&drm_dev->struct_mutex); @@ -182,9 +182,9 @@ i915_l3_write(struct file *filp, struct kobject *kobj, * at this point it is left as a TODO. */ if (temp) - dev_priv->mm.l3_remap_info = temp; + dev_priv->l3_parity.remap_info = temp; - memcpy(dev_priv->mm.l3_remap_info + (offset/4), + memcpy(dev_priv->l3_parity.remap_info + (offset/4), buf + (offset/4), count); @@ -211,12 +211,9 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; - + mutex_lock(&dev_priv->rps.hw_lock); ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d", ret); } @@ -228,12 +225,9 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; - + mutex_lock(&dev_priv->rps.hw_lock); ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d", ret); } @@ -254,16 +248,14 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, val /= GT_FREQUENCY_MULTIPLIER; - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; + mutex_lock(&dev_priv->rps.hw_lock); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); hw_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) { - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return -EINVAL; } @@ -272,7 +264,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, dev_priv->rps.max_delay = val; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return count; } @@ -284,12 +276,9 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; - + mutex_lock(&dev_priv->rps.hw_lock); ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d", ret); } @@ -310,16 +299,14 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, val /= GT_FREQUENCY_MULTIPLIER; - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; + mutex_lock(&dev_priv->rps.hw_lock); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); hw_max = (rp_state_cap & 0xff); hw_min = ((rp_state_cap & 0xff0000) >> 16); if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return -EINVAL; } @@ -328,7 +315,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, dev_priv->rps.min_delay = val; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->rps.hw_lock); return count; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 8134421..3db4a68 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -229,24 +229,26 @@ TRACE_EVENT(i915_gem_evict_everything, ); TRACE_EVENT(i915_gem_ring_dispatch, - TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), - TP_ARGS(ring, seqno), + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno, u32 flags), + TP_ARGS(ring, seqno, flags), TP_STRUCT__entry( __field(u32, dev) __field(u32, ring) __field(u32, seqno) + __field(u32, flags) ), TP_fast_assign( __entry->dev = ring->dev->primary->index; __entry->ring = ring->id; __entry->seqno = seqno; + __entry->flags = flags; i915_trace_irq_get(ring, seqno); ), - TP_printk("dev=%u, ring=%u, seqno=%u", - __entry->dev, __entry->ring, __entry->seqno) + TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x", + __entry->dev, __entry->ring, __entry->seqno, __entry->flags) ); TRACE_EVENT(i915_gem_ring_flush, diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 56846ed..55ffba1 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -755,7 +755,8 @@ void intel_setup_bios(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Set the Panel Power On/Off timings if uninitialized. */ - if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) { + if (!HAS_PCH_SPLIT(dev) && + I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) { /* Set T2 to 40ms and T5 to 200ms */ I915_WRITE(PP_ON_DELAYS, 0x019007d0); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6345878..9293878 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -198,6 +198,11 @@ static int intel_crt_mode_valid(struct drm_connector *connector, if (mode->clock > max_clock) return MODE_CLOCK_HIGH; + /* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */ + if (HAS_PCH_LPT(dev) && + (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2)) + return MODE_CLOCK_HIGH; + return MODE_OK; } @@ -221,14 +226,20 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; u32 adpa; - adpa = ADPA_HOTPLUG_BITS; + if (HAS_PCH_SPLIT(dev)) + adpa = ADPA_HOTPLUG_BITS; + else + adpa = 0; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) adpa |= ADPA_HSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) adpa |= ADPA_VSYNC_ACTIVE_HIGH; /* For CPT allow 3 pipe config, for others just use A or B */ - if (HAS_PCH_CPT(dev)) + if (HAS_PCH_LPT(dev)) + ; /* Those bits don't exist here */ + else if (HAS_PCH_CPT(dev)) adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); else if (intel_crtc->pipe == 0) adpa |= ADPA_PIPE_A_SELECT; @@ -401,12 +412,16 @@ static int intel_crt_ddc_get_modes(struct drm_connector *connector, struct i2c_adapter *adapter) { struct edid *edid; + int ret; edid = intel_crt_get_edid(connector, adapter); if (!edid) return 0; - return intel_connector_update_modes(connector, edid); + ret = intel_connector_update_modes(connector, edid); + kfree(edid); + + return ret; } static bool intel_crt_detect_ddc(struct drm_connector *connector) @@ -644,10 +659,22 @@ static int intel_crt_set_property(struct drm_connector *connector, static void intel_crt_reset(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_attached_crt(connector); - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_SPLIT(dev)) { + u32 adpa; + + adpa = I915_READ(PCH_ADPA); + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + adpa |= ADPA_HOTPLUG_BITS; + I915_WRITE(PCH_ADPA, adpa); + POSTING_READ(PCH_ADPA); + + DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); crt->force_hotplug_required = 1; + } + } /* @@ -729,7 +756,7 @@ void intel_crt_init(struct drm_device *dev) crt->base.type = INTEL_OUTPUT_ANALOG; crt->base.cloneable = true; - if (IS_HASWELL(dev) || IS_I830(dev)) + if (IS_I830(dev)) crt->base.crtc_mask = (1 << 0); else crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); @@ -749,7 +776,10 @@ void intel_crt_init(struct drm_device *dev) crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; - crt->base.get_hw_state = intel_crt_get_hw_state; + if (IS_HASWELL(dev)) + crt->base.get_hw_state = intel_ddi_get_hw_state; + else + crt->base.get_hw_state = intel_crt_get_hw_state; intel_connector->get_hw_state = intel_connector_get_hw_state; drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs); @@ -766,18 +796,14 @@ void intel_crt_init(struct drm_device *dev) * Configure the automatic hotplug detection stuff */ crt->force_hotplug_required = 0; - if (HAS_PCH_SPLIT(dev)) { - u32 adpa; - - adpa = I915_READ(PCH_ADPA); - adpa &= ~ADPA_CRT_HOTPLUG_MASK; - adpa |= ADPA_HOTPLUG_BITS; - I915_WRITE(PCH_ADPA, adpa); - POSTING_READ(PCH_ADPA); - - DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); - crt->force_hotplug_required = 1; - } dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; + + /* + * TODO: find a proper way to discover whether we need to set the + * polarity reversal bit or not, instead of relying on the BIOS. + */ + if (HAS_PCH_LPT(dev)) + dev_priv->fdi_rx_polarity_reversed = + !!(I915_READ(_FDI_RXA_CTL) & FDI_RX_POLARITY_REVERSED_LPT); } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index bfe3754..4bad0f7 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -58,6 +58,26 @@ static const u32 hsw_ddi_translations_fdi[] = { 0x00FFFFFF, 0x00040006 /* HDMI parameters */ }; +static enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || + type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(encoder); + return intel_dig_port->port; + + } else if (type == INTEL_OUTPUT_ANALOG) { + return PORT_E; + + } else { + DRM_ERROR("Invalid DDI encoder type %d\n", type); + BUG(); + } +} + /* On Haswell, DDI port buffers must be programmed with correct values * in advance. The buffer values are different for FDI and DP modes, * but the HDMI/DVI fields are shared among those. So we program the DDI @@ -118,6 +138,19 @@ static const long hsw_ddi_buf_ctl_values[] = { DDI_BUF_EMP_800MV_3_5DB_HSW }; +static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port) +{ + uint32_t reg = DDI_BUF_CTL(port); + int i; + + for (i = 0; i < 8; i++) { + udelay(1); + if (I915_READ(reg) & DDI_BUF_IS_IDLE) + return; + } + DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); +} /* Starting with Haswell, different DDI ports can work in FDI mode for * connection to the PCH-located connectors. For this, it is necessary to train @@ -133,25 +166,36 @@ void hsw_fdi_link_train(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); - int pipe = intel_crtc->pipe; - u32 reg, temp, i; - - /* Configure CPU PLL, wait for warmup */ - I915_WRITE(SPLL_CTL, - SPLL_PLL_ENABLE | - SPLL_PLL_FREQ_1350MHz | - SPLL_PLL_SCC); + u32 temp, i, rx_ctl_val; - /* Use SPLL to drive the output when in FDI mode */ - I915_WRITE(PORT_CLK_SEL(PORT_E), - PORT_CLK_SEL_SPLL); - I915_WRITE(PIPE_CLK_SEL(pipe), - PIPE_CLK_SEL_PORT(PORT_E)); - - udelay(20); - - /* Start the training iterating through available voltages and emphasis */ - for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) { + /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the + * mode set "sequence for CRT port" document: + * - TP1 to TP2 time with the default value + * - FDI delay to 90h + */ + I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | + FDI_RX_PWRDN_LANE0_VAL(2) | + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + + /* Enable the PCH Receiver FDI PLL */ + rx_ctl_val = FDI_RX_PLL_ENABLE | FDI_RX_ENHANCE_FRAME_ENABLE | + ((intel_crtc->fdi_lanes - 1) << 19); + if (dev_priv->fdi_rx_polarity_reversed) + rx_ctl_val |= FDI_RX_POLARITY_REVERSED_LPT; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + POSTING_READ(_FDI_RXA_CTL); + udelay(220); + + /* Switch from Rawclk to PCDclk */ + rx_ctl_val |= FDI_PCDCLK; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + + /* Configure Port Clock Select */ + I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->ddi_pll_sel); + + /* Start the training iterating through available voltages and emphasis, + * testing each value twice. */ + for (i = 0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values) * 2; i++) { /* Configure DP_TP_CTL with auto-training */ I915_WRITE(DP_TP_CTL(PORT_E), DP_TP_CTL_FDI_AUTOTRAIN | @@ -160,103 +204,75 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) DP_TP_CTL_ENABLE); /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */ - temp = I915_READ(DDI_BUF_CTL(PORT_E)); - temp = (temp & ~DDI_BUF_EMP_MASK); I915_WRITE(DDI_BUF_CTL(PORT_E), - temp | - DDI_BUF_CTL_ENABLE | - DDI_PORT_WIDTH_X2 | - hsw_ddi_buf_ctl_values[i]); + DDI_BUF_CTL_ENABLE | + ((intel_crtc->fdi_lanes - 1) << 1) | + hsw_ddi_buf_ctl_values[i / 2]); + POSTING_READ(DDI_BUF_CTL(PORT_E)); udelay(600); - /* We need to program FDI_RX_MISC with the default TP1 to TP2 - * values before enabling the receiver, and configure the delay - * for the FDI timing generator to 90h. Luckily, all the other - * bits are supposed to be zeroed, so we can write those values - * directly. - */ - I915_WRITE(FDI_RX_MISC(pipe), FDI_RX_TP1_TO_TP2_48 | - FDI_RX_FDI_DELAY_90); - - /* Enable CPU FDI Receiver with auto-training */ - reg = FDI_RX_CTL(pipe); - I915_WRITE(reg, - I915_READ(reg) | - FDI_LINK_TRAIN_AUTO | - FDI_RX_ENABLE | - FDI_LINK_TRAIN_PATTERN_1_CPT | - FDI_RX_ENHANCE_FRAME_ENABLE | - FDI_PORT_WIDTH_2X_LPT | - FDI_RX_PLL_ENABLE); - POSTING_READ(reg); - udelay(100); + /* Program PCH FDI Receiver TU */ + I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64)); + + /* Enable PCH FDI Receiver with auto-training */ + rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + POSTING_READ(_FDI_RXA_CTL); + + /* Wait for FDI receiver lane calibration */ + udelay(30); + + /* Unset FDI_RX_MISC pwrdn lanes */ + temp = I915_READ(_FDI_RXA_MISC); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + I915_WRITE(_FDI_RXA_MISC, temp); + POSTING_READ(_FDI_RXA_MISC); + + /* Wait for FDI auto training time */ + udelay(5); temp = I915_READ(DP_TP_STATUS(PORT_E)); if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { - DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i); + DRM_DEBUG_KMS("FDI link training done on step %d\n", i); /* Enable normal pixel sending for FDI */ I915_WRITE(DP_TP_CTL(PORT_E), - DP_TP_CTL_FDI_AUTOTRAIN | - DP_TP_CTL_LINK_TRAIN_NORMAL | - DP_TP_CTL_ENHANCED_FRAME_ENABLE | - DP_TP_CTL_ENABLE); - - /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */ - temp = I915_READ(DDI_FUNC_CTL(pipe)); - temp &= ~PIPE_DDI_PORT_MASK; - temp |= PIPE_DDI_SELECT_PORT(PORT_E) | - PIPE_DDI_MODE_SELECT_FDI | - PIPE_DDI_FUNC_ENABLE | - PIPE_DDI_PORT_WIDTH_X2; - I915_WRITE(DDI_FUNC_CTL(pipe), - temp); - break; - } else { - DRM_ERROR("Error training BUF_CTL %d\n", i); + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_LINK_TRAIN_NORMAL | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_ENABLE); - /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */ - I915_WRITE(DP_TP_CTL(PORT_E), - I915_READ(DP_TP_CTL(PORT_E)) & - ~DP_TP_CTL_ENABLE); - I915_WRITE(FDI_RX_CTL(pipe), - I915_READ(FDI_RX_CTL(pipe)) & - ~FDI_RX_PLL_ENABLE); - continue; + return; } - } - DRM_DEBUG_KMS("FDI train done.\n"); -} - -/* For DDI connections, it is possible to support different outputs over the - * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by - * the time the output is detected what exactly is on the other end of it. This - * function aims at providing support for this detection and proper output - * configuration. - */ -void intel_ddi_init(struct drm_device *dev, enum port port) -{ - /* For now, we don't do any proper output detection and assume that we - * handle HDMI only */ - - switch(port){ - case PORT_A: - /* We don't handle eDP and DP yet */ - DRM_DEBUG_DRIVER("Found digital output on DDI port A\n"); - break; - /* Assume that the ports B, C and D are working in HDMI mode for now */ - case PORT_B: - case PORT_C: - case PORT_D: - intel_hdmi_init(dev, DDI_BUF_CTL(port), port); - break; - default: - DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n", - port); - break; + temp = I915_READ(DDI_BUF_CTL(PORT_E)); + temp &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(PORT_E), temp); + POSTING_READ(DDI_BUF_CTL(PORT_E)); + + /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ + temp = I915_READ(DP_TP_CTL(PORT_E)); + temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + temp |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(PORT_E), temp); + POSTING_READ(DP_TP_CTL(PORT_E)); + + intel_wait_ddi_buf_idle(dev_priv, PORT_E); + + rx_ctl_val &= ~FDI_RX_ENABLE; + I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + POSTING_READ(_FDI_RXA_CTL); + + /* Reset FDI_RX_MISC pwrdn lanes */ + temp = I915_READ(_FDI_RXA_MISC); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); + I915_WRITE(_FDI_RXA_MISC, temp); + POSTING_READ(_FDI_RXA_MISC); } + + DRM_ERROR("FDI link training failed!\n"); } /* WRPLL clock dividers */ @@ -645,116 +661,435 @@ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { {298000, 2, 21, 19}, }; -void intel_ddi_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void intel_ddi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - int port = intel_hdmi->ddi_port; + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + int port = intel_ddi_get_encoder_port(intel_encoder); int pipe = intel_crtc->pipe; - int p, n2, r2; - u32 temp, i; + int type = intel_encoder->type; - /* On Haswell, we need to enable the clocks and prepare DDI function to - * work in HDMI mode for this pipe. - */ - DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); + DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n", + port_name(port), pipe_name(pipe)); + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_dp->DP = DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; + switch (intel_dp->lane_count) { + case 1: + intel_dp->DP |= DDI_PORT_WIDTH_X1; + break; + case 2: + intel_dp->DP |= DDI_PORT_WIDTH_X2; + break; + case 4: + intel_dp->DP |= DDI_PORT_WIDTH_X4; + break; + default: + intel_dp->DP |= DDI_PORT_WIDTH_X4; + WARN(1, "Unexpected DP lane count %d\n", + intel_dp->lane_count); + break; + } + + if (intel_dp->has_audio) { + DRM_DEBUG_DRIVER("DP audio on pipe %c on DDI\n", + pipe_name(intel_crtc->pipe)); + + /* write eld */ + DRM_DEBUG_DRIVER("DP audio: write eld information\n"); + intel_write_eld(encoder, adjusted_mode); + } + + intel_dp_init_link_config(intel_dp); + + } else if (type == INTEL_OUTPUT_HDMI) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (intel_hdmi->has_audio) { + /* Proper support for digital audio needs a new logic + * and a new set of registers, so we leave it for future + * patch bombing. + */ + DRM_DEBUG_DRIVER("HDMI audio on pipe %c on DDI\n", + pipe_name(intel_crtc->pipe)); + + /* write eld */ + DRM_DEBUG_DRIVER("HDMI audio: write eld information\n"); + intel_write_eld(encoder, adjusted_mode); + } + + intel_hdmi->set_infoframes(encoder, adjusted_mode); + } +} + +static struct intel_encoder * +intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *intel_encoder, *ret = NULL; + int num_encoders = 0; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + ret = intel_encoder; + num_encoders++; + } + + if (num_encoders != 1) + WARN(1, "%d encoders on crtc for pipe %d\n", num_encoders, + intel_crtc->pipe); + + BUG_ON(ret == NULL); + return ret; +} + +void intel_ddi_put_crtc_pll(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t val; + + switch (intel_crtc->ddi_pll_sel) { + case PORT_CLK_SEL_SPLL: + plls->spll_refcount--; + if (plls->spll_refcount == 0) { + DRM_DEBUG_KMS("Disabling SPLL\n"); + val = I915_READ(SPLL_CTL); + WARN_ON(!(val & SPLL_PLL_ENABLE)); + I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE); + POSTING_READ(SPLL_CTL); + } + break; + case PORT_CLK_SEL_WRPLL1: + plls->wrpll1_refcount--; + if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Disabling WRPLL 1\n"); + val = I915_READ(WRPLL_CTL1); + WARN_ON(!(val & WRPLL_PLL_ENABLE)); + I915_WRITE(WRPLL_CTL1, val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL1); + } + break; + case PORT_CLK_SEL_WRPLL2: + plls->wrpll2_refcount--; + if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Disabling WRPLL 2\n"); + val = I915_READ(WRPLL_CTL2); + WARN_ON(!(val & WRPLL_PLL_ENABLE)); + I915_WRITE(WRPLL_CTL2, val & ~WRPLL_PLL_ENABLE); + POSTING_READ(WRPLL_CTL2); + } + break; + } + + WARN(plls->spll_refcount < 0, "Invalid SPLL refcount\n"); + WARN(plls->wrpll1_refcount < 0, "Invalid WRPLL1 refcount\n"); + WARN(plls->wrpll2_refcount < 0, "Invalid WRPLL2 refcount\n"); + + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE; +} + +static void intel_ddi_calculate_wrpll(int clock, int *p, int *n2, int *r2) +{ + u32 i; for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) - if (crtc->mode.clock <= wrpll_tmds_clock_table[i].clock) + if (clock <= wrpll_tmds_clock_table[i].clock) break; if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) i--; - p = wrpll_tmds_clock_table[i].p; - n2 = wrpll_tmds_clock_table[i].n2; - r2 = wrpll_tmds_clock_table[i].r2; + *p = wrpll_tmds_clock_table[i].p; + *n2 = wrpll_tmds_clock_table[i].n2; + *r2 = wrpll_tmds_clock_table[i].r2; - if (wrpll_tmds_clock_table[i].clock != crtc->mode.clock) - DRM_INFO("WR PLL: using settings for %dKHz on %dKHz mode\n", - wrpll_tmds_clock_table[i].clock, crtc->mode.clock); + if (wrpll_tmds_clock_table[i].clock != clock) + DRM_INFO("WRPLL: using settings for %dKHz on %dKHz mode\n", + wrpll_tmds_clock_table[i].clock, clock); - DRM_DEBUG_KMS("WR PLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", - crtc->mode.clock, p, n2, r2); + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, *p, *n2, *r2); +} - /* Enable LCPLL if disabled */ - temp = I915_READ(LCPLL_CTL); - if (temp & LCPLL_PLL_DISABLE) - I915_WRITE(LCPLL_CTL, - temp & ~LCPLL_PLL_DISABLE); +bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) +{ + 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; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int type = intel_encoder->type; + enum pipe pipe = intel_crtc->pipe; + uint32_t reg, val; - /* Configure WR PLL 1, program the correct divider values for - * the desired frequency and wait for warmup */ - I915_WRITE(WRPLL_CTL1, - WRPLL_PLL_ENABLE | - WRPLL_PLL_SELECT_LCPLL_2700 | - WRPLL_DIVIDER_REFERENCE(r2) | - WRPLL_DIVIDER_FEEDBACK(n2) | - WRPLL_DIVIDER_POST(p)); + /* TODO: reuse PLLs when possible (compare values) */ - udelay(20); + intel_ddi_put_crtc_pll(crtc); - /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use - * this port for connection. - */ - I915_WRITE(PORT_CLK_SEL(port), - PORT_CLK_SEL_WRPLL1); - I915_WRITE(PIPE_CLK_SEL(pipe), - PIPE_CLK_SEL_PORT(port)); + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + switch (intel_dp->link_bw) { + case DP_LINK_BW_1_62: + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810; + break; + case DP_LINK_BW_2_7: + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350; + break; + case DP_LINK_BW_5_4: + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700; + break; + default: + DRM_ERROR("Link bandwidth %d unsupported\n", + intel_dp->link_bw); + return false; + } + + /* We don't need to turn any PLL on because we'll use LCPLL. */ + return true; + + } else if (type == INTEL_OUTPUT_HDMI) { + int p, n2, r2; + + if (plls->wrpll1_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", + pipe_name(pipe)); + plls->wrpll1_refcount++; + reg = WRPLL_CTL1; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; + } else if (plls->wrpll2_refcount == 0) { + DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n", + pipe_name(pipe)); + plls->wrpll2_refcount++; + reg = WRPLL_CTL2; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2; + } else { + DRM_ERROR("No WRPLLs available!\n"); + return false; + } + WARN(I915_READ(reg) & WRPLL_PLL_ENABLE, + "WRPLL already enabled\n"); + + intel_ddi_calculate_wrpll(clock, &p, &n2, &r2); + + val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p); + + } else if (type == INTEL_OUTPUT_ANALOG) { + if (plls->spll_refcount == 0) { + DRM_DEBUG_KMS("Using SPLL on pipe %c\n", + pipe_name(pipe)); + plls->spll_refcount++; + reg = SPLL_CTL; + intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; + } + + WARN(I915_READ(reg) & SPLL_PLL_ENABLE, + "SPLL already enabled\n"); + + val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC; + + } else { + WARN(1, "Invalid DDI encoder type %d\n", type); + return false; + } + + I915_WRITE(reg, val); udelay(20); - if (intel_hdmi->has_audio) { - /* Proper support for digital audio needs a new logic and a new set - * of registers, so we leave it for future patch bombing. - */ - DRM_DEBUG_DRIVER("HDMI audio on pipe %c on DDI\n", - pipe_name(intel_crtc->pipe)); + return true; +} - /* write eld */ - DRM_DEBUG_DRIVER("HDMI audio: write eld information\n"); - intel_write_eld(encoder, adjusted_mode); +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; + 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) { + case 18: + temp |= TRANS_MSA_6_BPC; + break; + case 24: + temp |= TRANS_MSA_8_BPC; + break; + case 30: + temp |= TRANS_MSA_10_BPC; + break; + case 36: + temp |= TRANS_MSA_12_BPC; + break; + default: + temp |= TRANS_MSA_8_BPC; + WARN(1, "%d bpp unsupported by DDI function\n", + intel_crtc->bpp); + } + I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); } +} - /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */ - temp = PIPE_DDI_FUNC_ENABLE | PIPE_DDI_SELECT_PORT(port); +void intel_ddi_enable_pipe_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 port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + uint32_t temp; + + /* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */ + temp = TRANS_DDI_FUNC_ENABLE; + temp |= TRANS_DDI_SELECT_PORT(port); switch (intel_crtc->bpp) { case 18: - temp |= PIPE_DDI_BPC_6; + temp |= TRANS_DDI_BPC_6; break; case 24: - temp |= PIPE_DDI_BPC_8; + temp |= TRANS_DDI_BPC_8; break; case 30: - temp |= PIPE_DDI_BPC_10; + temp |= TRANS_DDI_BPC_10; break; case 36: - temp |= PIPE_DDI_BPC_12; + temp |= TRANS_DDI_BPC_12; break; default: - WARN(1, "%d bpp unsupported by pipe DDI function\n", + WARN(1, "%d bpp unsupported by transcoder DDI function\n", intel_crtc->bpp); } - if (intel_hdmi->has_hdmi_sink) - temp |= PIPE_DDI_MODE_SELECT_HDMI; + if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) + temp |= TRANS_DDI_PVSYNC; + if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) + temp |= TRANS_DDI_PHSYNC; + + if (cpu_transcoder == TRANSCODER_EDP) { + switch (pipe) { + case PIPE_A: + temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + break; + case PIPE_B: + temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; + break; + case PIPE_C: + temp |= TRANS_DDI_EDP_INPUT_C_ONOFF; + break; + default: + BUG(); + break; + } + } + + if (type == INTEL_OUTPUT_HDMI) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (intel_hdmi->has_hdmi_sink) + temp |= TRANS_DDI_MODE_SELECT_HDMI; + else + temp |= TRANS_DDI_MODE_SELECT_DVI; + + } else if (type == INTEL_OUTPUT_ANALOG) { + temp |= TRANS_DDI_MODE_SELECT_FDI; + temp |= (intel_crtc->fdi_lanes - 1) << 1; + + } else if (type == INTEL_OUTPUT_DISPLAYPORT || + type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + temp |= TRANS_DDI_MODE_SELECT_DP_SST; + + switch (intel_dp->lane_count) { + case 1: + temp |= TRANS_DDI_PORT_WIDTH_X1; + break; + case 2: + temp |= TRANS_DDI_PORT_WIDTH_X2; + break; + case 4: + temp |= TRANS_DDI_PORT_WIDTH_X4; + break; + default: + temp |= TRANS_DDI_PORT_WIDTH_X4; + WARN(1, "Unsupported lane count %d\n", + intel_dp->lane_count); + } + + } else { + WARN(1, "Invalid encoder type %d for pipe %d\n", + intel_encoder->type, pipe); + } + + I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); +} + +void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) +{ + uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); + uint32_t val = I915_READ(reg); + + val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK); + val |= TRANS_DDI_PORT_NONE; + I915_WRITE(reg, val); +} + +bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) +{ + struct drm_device *dev = intel_connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder = intel_connector->encoder; + int type = intel_connector->base.connector_type; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + enum pipe pipe = 0; + enum transcoder cpu_transcoder; + uint32_t tmp; + + if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) + return false; + + if (port == PORT_A) + cpu_transcoder = TRANSCODER_EDP; else - temp |= PIPE_DDI_MODE_SELECT_DVI; + cpu_transcoder = pipe; + + tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); - if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - temp |= PIPE_DDI_PVSYNC; - if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - temp |= PIPE_DDI_PHSYNC; + switch (tmp & TRANS_DDI_MODE_SELECT_MASK) { + case TRANS_DDI_MODE_SELECT_HDMI: + case TRANS_DDI_MODE_SELECT_DVI: + return (type == DRM_MODE_CONNECTOR_HDMIA); + + case TRANS_DDI_MODE_SELECT_DP_SST: + if (type == DRM_MODE_CONNECTOR_eDP) + return true; + case TRANS_DDI_MODE_SELECT_DP_MST: + return (type == DRM_MODE_CONNECTOR_DisplayPort); - I915_WRITE(DDI_FUNC_CTL(pipe), temp); + case TRANS_DDI_MODE_SELECT_FDI: + return (type == DRM_MODE_CONNECTOR_VGA); - intel_hdmi->set_infoframes(encoder, adjusted_mode); + default: + return false; + } } bool intel_ddi_get_hw_state(struct intel_encoder *encoder, @@ -762,58 +1097,418 @@ bool intel_ddi_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_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + enum port port = intel_ddi_get_encoder_port(encoder); u32 tmp; int i; - tmp = I915_READ(DDI_BUF_CTL(intel_hdmi->ddi_port)); + tmp = I915_READ(DDI_BUF_CTL(port)); if (!(tmp & DDI_BUF_CTL_ENABLE)) return false; - for_each_pipe(i) { - tmp = I915_READ(DDI_FUNC_CTL(i)); + if (port == PORT_A) { + tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); - if ((tmp & PIPE_DDI_PORT_MASK) - == PIPE_DDI_SELECT_PORT(intel_hdmi->ddi_port)) { - *pipe = i; - return true; + switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { + case TRANS_DDI_EDP_INPUT_A_ON: + case TRANS_DDI_EDP_INPUT_A_ONOFF: + *pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + *pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + *pipe = PIPE_C; + break; + } + + return true; + } else { + for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) { + tmp = I915_READ(TRANS_DDI_FUNC_CTL(i)); + + if ((tmp & TRANS_DDI_PORT_MASK) + == TRANS_DDI_SELECT_PORT(port)) { + *pipe = i; + return true; + } } } - DRM_DEBUG_KMS("No pipe for ddi port %i found\n", intel_hdmi->ddi_port); + DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); return true; } -void intel_enable_ddi(struct intel_encoder *encoder) +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 transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + int i; + + if (cpu_transcoder == TRANSCODER_EDP) { + port = PORT_A; + } else { + temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); + temp &= TRANS_DDI_PORT_MASK; + + for (i = PORT_B; i <= PORT_E; i++) + if (temp == TRANS_DDI_SELECT_PORT(i)) + 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); + + return ret; +} + +void intel_ddi_setup_hw_pll_state(struct drm_device *dev) { - struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); - int port = intel_hdmi->ddi_port; - u32 temp; + enum pipe pipe; + struct intel_crtc *intel_crtc; - temp = I915_READ(DDI_BUF_CTL(port)); - temp |= DDI_BUF_CTL_ENABLE; + for_each_pipe(pipe) { + intel_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width, - * and swing/emphasis values are ignored so nothing special needs - * to be done besides enabling the port. - */ - I915_WRITE(DDI_BUF_CTL(port), temp); + if (!intel_crtc->active) + continue; + + intel_crtc->ddi_pll_sel = intel_ddi_get_crtc_pll(dev_priv, + pipe); + + switch (intel_crtc->ddi_pll_sel) { + case PORT_CLK_SEL_SPLL: + dev_priv->ddi_plls.spll_refcount++; + break; + case PORT_CLK_SEL_WRPLL1: + dev_priv->ddi_plls.wrpll1_refcount++; + break; + case PORT_CLK_SEL_WRPLL2: + dev_priv->ddi_plls.wrpll2_refcount++; + break; + } + } } -void intel_disable_ddi(struct intel_encoder *encoder) +void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) { - struct drm_device *dev = encoder->base.dev; + struct drm_crtc *crtc = &intel_crtc->base; + 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; + + if (cpu_transcoder != TRANSCODER_EDP) + I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), + TRANS_CLK_SEL_PORT(port)); +} + +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; + + if (cpu_transcoder != TRANSCODER_EDP) + I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), + TRANS_CLK_SEL_DISABLED); +} + +static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + ironlake_edp_panel_vdd_on(intel_dp); + ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp, true); + } + + WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); + I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_start_link_train(intel_dp); + intel_dp_complete_link_train(intel_dp); + } +} + +static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + uint32_t val; + bool wait = false; + + val = I915_READ(DDI_BUF_CTL(port)); + if (val & DDI_BUF_CTL_ENABLE) { + val &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), val); + wait = true; + } + + val = I915_READ(DP_TP_CTL(port)); + val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + val |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(port), val); + + if (wait) + intel_wait_ddi_buf_idle(dev_priv, port); + + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + ironlake_edp_panel_vdd_on(intel_dp); + ironlake_edp_panel_off(intel_dp); + } + + I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); +} + +static void intel_enable_ddi(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); - int port = intel_hdmi->ddi_port; - u32 temp; + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_HDMI) { + /* In HDMI/DVI mode, the port width, and swing/emphasis values + * are ignored so nothing special needs to be done besides + * enabling the port. + */ + I915_WRITE(DDI_BUF_CTL(port), DDI_BUF_CTL_ENABLE); + } else if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + ironlake_edp_backlight_on(intel_dp); + } +} + +static void intel_disable_ddi(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + ironlake_edp_backlight_off(intel_dp); + } +} + +int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) +{ + if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) + return 450; + else if ((I915_READ(LCPLL_CTL) & LCPLL_CLK_FREQ_MASK) == + LCPLL_CLK_FREQ_450) + return 450; + else if (IS_ULT(dev_priv->dev)) + return 338; + else + return 540; +} + +void intel_ddi_pll_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val = I915_READ(LCPLL_CTL); + + /* The LCPLL register should be turned on by the BIOS. For now let's + * just check its state and print errors in case something is wrong. + * Don't even try to turn it on. + */ + + DRM_DEBUG_KMS("CDCLK running at %dMHz\n", + intel_ddi_get_cdclk_freq(dev_priv)); + + if (val & LCPLL_CD_SOURCE_FCLK) + DRM_ERROR("CDCLK source is not LCPLL\n"); + + if (val & LCPLL_PLL_DISABLE) + DRM_ERROR("LCPLL is disabled\n"); +} + +void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) +{ + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_dp *intel_dp = &intel_dig_port->dp; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + enum port port = intel_dig_port->port; + bool wait; + uint32_t val; + + if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { + val = I915_READ(DDI_BUF_CTL(port)); + if (val & DDI_BUF_CTL_ENABLE) { + val &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), val); + wait = true; + } + + val = I915_READ(DP_TP_CTL(port)); + val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + val |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); + + if (wait) + intel_wait_ddi_buf_idle(dev_priv, port); + } + + val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST | + DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; + if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) + val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); + + intel_dp->DP |= DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP); + POSTING_READ(DDI_BUF_CTL(port)); + + udelay(600); +} + +void intel_ddi_fdi_disable(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + uint32_t val; + + intel_ddi_post_disable(intel_encoder); + + val = I915_READ(_FDI_RXA_CTL); + val &= ~FDI_RX_ENABLE; + I915_WRITE(_FDI_RXA_CTL, val); + + val = I915_READ(_FDI_RXA_MISC); + val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); + I915_WRITE(_FDI_RXA_MISC, val); + + val = I915_READ(_FDI_RXA_CTL); + val &= ~FDI_PCDCLK; + I915_WRITE(_FDI_RXA_CTL, val); + + val = I915_READ(_FDI_RXA_CTL); + val &= ~FDI_RX_PLL_ENABLE; + I915_WRITE(_FDI_RXA_CTL, val); +} + +static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); + int type = intel_encoder->type; + + if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) + intel_dp_check_link_status(intel_dp); +} + +static void intel_ddi_destroy(struct drm_encoder *encoder) +{ + /* HDMI has nothing special to destroy, so we can go with this. */ + 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) +{ + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + int type = intel_encoder->type; + + WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n"); + + if (type == INTEL_OUTPUT_HDMI) + return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode); + else + return intel_dp_mode_fixup(encoder, mode, adjusted_mode); +} + +static const struct drm_encoder_funcs intel_ddi_funcs = { + .destroy = intel_ddi_destroy, +}; + +static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { + .mode_fixup = intel_ddi_mode_fixup, + .mode_set = intel_ddi_mode_set, + .disable = intel_encoder_noop, +}; + +void intel_ddi_init(struct drm_device *dev, enum port port) +{ + struct intel_digital_port *intel_dig_port; + struct intel_encoder *intel_encoder; + struct drm_encoder *encoder; + struct intel_connector *hdmi_connector = NULL; + struct intel_connector *dp_connector = NULL; + + intel_dig_port = kzalloc(sizeof(struct intel_digital_port), GFP_KERNEL); + if (!intel_dig_port) + return; + + dp_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); + if (!dp_connector) { + kfree(intel_dig_port); + return; + } + + if (port != PORT_A) { + hdmi_connector = kzalloc(sizeof(struct intel_connector), + GFP_KERNEL); + if (!hdmi_connector) { + kfree(dp_connector); + kfree(intel_dig_port); + return; + } + } + + intel_encoder = &intel_dig_port->base; + encoder = &intel_encoder->base; + + drm_encoder_init(dev, encoder, &intel_ddi_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); + + intel_encoder->enable = intel_enable_ddi; + intel_encoder->pre_enable = intel_ddi_pre_enable; + intel_encoder->disable = intel_disable_ddi; + intel_encoder->post_disable = intel_ddi_post_disable; + intel_encoder->get_hw_state = intel_ddi_get_hw_state; + + intel_dig_port->port = port; + if (hdmi_connector) + intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); + else + intel_dig_port->hdmi.sdvox_reg = 0; + intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); - temp = I915_READ(DDI_BUF_CTL(port)); - temp &= ~DDI_BUF_CTL_ENABLE; + intel_encoder->type = INTEL_OUTPUT_UNKNOWN; + intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + intel_encoder->cloneable = false; + intel_encoder->hot_plug = intel_ddi_hot_plug; - I915_WRITE(DDI_BUF_CTL(port), temp); + if (hdmi_connector) + intel_hdmi_init_connector(intel_dig_port, hdmi_connector); + intel_dp_init_connector(intel_dig_port, dp_connector); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b426d44..5d127e0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -41,8 +41,6 @@ #include <drm/drm_crtc_helper.h> #include <linux/dma_remapping.h> -#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) - bool intel_pipe_has_type(struct drm_crtc *crtc, int type); static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); @@ -80,6 +78,16 @@ struct intel_limit { /* FDI */ #define IRONLAKE_FDI_FREQ 2700000 /* in kHz for mode->clock */ +int +intel_pch_rawclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_PCH_SPLIT(dev)); + + return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK; +} + static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, @@ -380,7 +388,7 @@ static const intel_limit_t intel_limits_vlv_dac = { static const intel_limit_t intel_limits_vlv_hdmi = { .dot = { .min = 20000, .max = 165000 }, - .vco = { .min = 5994000, .max = 4000000 }, + .vco = { .min = 4000000, .max = 5994000}, .n = { .min = 1, .max = 7 }, .m = { .min = 60, .max = 300 }, /* guess */ .m1 = { .min = 2, .max = 3 }, @@ -393,10 +401,10 @@ static const intel_limit_t intel_limits_vlv_hdmi = { }; static const intel_limit_t intel_limits_vlv_dp = { - .dot = { .min = 162000, .max = 270000 }, - .vco = { .min = 5994000, .max = 4000000 }, + .dot = { .min = 25000, .max = 270000 }, + .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, - .m = { .min = 60, .max = 300 }, /* guess */ + .m = { .min = 22, .max = 450 }, .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, @@ -531,7 +539,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, limit = &intel_limits_ironlake_single_lvds; } } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || - HAS_eDP) + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) limit = &intel_limits_ironlake_display_port; else limit = &intel_limits_ironlake_dac; @@ -927,6 +935,15 @@ intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, return true; } +enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + 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; +} + static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -999,9 +1016,11 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); if (INTEL_INFO(dev)->gen >= 4) { - int reg = PIPECONF(pipe); + int reg = PIPECONF(cpu_transcoder); /* Wait for the Pipe State to go off */ if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, @@ -1103,12 +1122,14 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, int reg; u32 val; bool cur_state; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); if (IS_HASWELL(dev_priv->dev)) { /* On Haswell, DDI is used instead of FDI_TX_CTL */ - reg = DDI_FUNC_CTL(pipe); + reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); val = I915_READ(reg); - cur_state = !!(val & PIPE_DDI_FUNC_ENABLE); + cur_state = !!(val & TRANS_DDI_FUNC_ENABLE); } else { reg = FDI_TX_CTL(pipe); val = I915_READ(reg); @@ -1128,14 +1149,9 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv, u32 val; bool cur_state; - if (IS_HASWELL(dev_priv->dev) && pipe > 0) { - DRM_ERROR("Attempting to enable FDI_RX on Haswell pipe > 0\n"); - return; - } else { - reg = FDI_RX_CTL(pipe); - val = I915_READ(reg); - cur_state = !!(val & FDI_RX_ENABLE); - } + reg = FDI_RX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_RX_ENABLE); WARN(cur_state != state, "FDI RX state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); @@ -1168,10 +1184,6 @@ static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv, int reg; u32 val; - if (IS_HASWELL(dev_priv->dev) && pipe > 0) { - DRM_ERROR("Attempting to enable FDI on Haswell with pipe > 0\n"); - return; - } reg = FDI_RX_CTL(pipe); val = I915_READ(reg); WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n"); @@ -1212,12 +1224,14 @@ void assert_pipe(struct drm_i915_private *dev_priv, int reg; u32 val; bool cur_state; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); /* if we need the pipe A quirk it must be always on */ if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - reg = PIPECONF(pipe); + reg = PIPECONF(cpu_transcoder); val = I915_READ(reg); cur_state = !!(val & PIPECONF_ENABLE); WARN(cur_state != state, @@ -1492,24 +1506,26 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) /* SBI access */ static void -intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value) +intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, + enum intel_sbi_destination destination) { unsigned long flags; + u32 tmp; spin_lock_irqsave(&dev_priv->dpio_lock, flags); - if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, - 100)) { + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to become ready\n"); goto out_unlock; } - I915_WRITE(SBI_ADDR, - (reg << 16)); - I915_WRITE(SBI_DATA, - value); - I915_WRITE(SBI_CTL_STAT, - SBI_BUSY | - SBI_CTL_OP_CRWR); + I915_WRITE(SBI_ADDR, (reg << 16)); + I915_WRITE(SBI_DATA, value); + + if (destination == SBI_ICLK) + tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR; + else + tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR; + I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp); if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, 100)) { @@ -1522,23 +1538,25 @@ out_unlock: } static u32 -intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg) +intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, + enum intel_sbi_destination destination) { unsigned long flags; u32 value = 0; spin_lock_irqsave(&dev_priv->dpio_lock, flags); - if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, - 100)) { + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to become ready\n"); goto out_unlock; } - I915_WRITE(SBI_ADDR, - (reg << 16)); - I915_WRITE(SBI_CTL_STAT, - SBI_BUSY | - SBI_CTL_OP_CRRD); + I915_WRITE(SBI_ADDR, (reg << 16)); + + if (destination == SBI_ICLK) + value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD; + else + value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD; + I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY); if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, 100)) { @@ -1554,14 +1572,14 @@ out_unlock: } /** - * intel_enable_pch_pll - enable PCH PLL + * ironlake_enable_pch_pll - enable PCH PLL * @dev_priv: i915 private structure * @pipe: pipe PLL to enable * * The PCH PLL needs to be enabled before the PCH transcoder, since it * drives the transcoder clock. */ -static void intel_enable_pch_pll(struct intel_crtc *intel_crtc) +static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) { struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; struct intel_pch_pll *pll; @@ -1645,12 +1663,12 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) pll->on = false; } -static void intel_enable_transcoder(struct drm_i915_private *dev_priv, - enum pipe pipe) +static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) { - int reg; - u32 val, pipeconf_val; + struct drm_device *dev = dev_priv->dev; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + uint32_t reg, val, pipeconf_val; /* PCH only available on ILK+ */ BUG_ON(dev_priv->info->gen < 5); @@ -1664,10 +1682,15 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv, assert_fdi_tx_enabled(dev_priv, pipe); assert_fdi_rx_enabled(dev_priv, pipe); - if (IS_HASWELL(dev_priv->dev) && pipe > 0) { - DRM_ERROR("Attempting to enable transcoder on Haswell with pipe > 0\n"); - return; + if (HAS_PCH_CPT(dev)) { + /* Workaround: Set the timing override bit before enabling the + * pch transcoder. */ + reg = TRANS_CHICKEN2(pipe); + val = I915_READ(reg); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(reg, val); } + reg = TRANSCONF(pipe); val = I915_READ(reg); pipeconf_val = I915_READ(PIPECONF(pipe)); @@ -1696,11 +1719,42 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv, DRM_ERROR("failed to enable transcoder %d\n", pipe); } -static void intel_disable_transcoder(struct drm_i915_private *dev_priv, - enum pipe pipe) +static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) { - int reg; - u32 val; + u32 val, pipeconf_val; + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + + /* FDI must be feeding us bits for PCH ports */ + assert_fdi_tx_enabled(dev_priv, cpu_transcoder); + assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); + + /* Workaround: set timing override bit. */ + val = I915_READ(_TRANSA_CHICKEN2); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(_TRANSA_CHICKEN2, val); + + val = TRANS_ENABLE; + pipeconf_val = I915_READ(PIPECONF(cpu_transcoder)); + + if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) == + PIPECONF_INTERLACED_ILK) + val |= TRANS_INTERLACED; + else + val |= TRANS_PROGRESSIVE; + + I915_WRITE(TRANSCONF(TRANSCODER_A), val); + if (wait_for(I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("Failed to enable PCH transcoder\n"); +} + +static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + struct drm_device *dev = dev_priv->dev; + uint32_t reg, val; /* FDI relies on the transcoder */ assert_fdi_tx_disabled(dev_priv, pipe); @@ -1716,6 +1770,31 @@ static void intel_disable_transcoder(struct drm_i915_private *dev_priv, /* wait for PCH transcoder off, transcoder state */ if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) DRM_ERROR("failed to disable transcoder %d\n", pipe); + + if (!HAS_PCH_IBX(dev)) { + /* Workaround: Clear the timing override chicken bit again. */ + reg = TRANS_CHICKEN2(pipe); + val = I915_READ(reg); + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(reg, val); + } +} + +static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) +{ + u32 val; + + val = I915_READ(_TRANSACONF); + val &= ~TRANS_ENABLE; + I915_WRITE(_TRANSACONF, val); + /* wait for PCH transcoder off, transcoder state */ + if (wait_for((I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE) == 0, 50)) + DRM_ERROR("Failed to disable PCH transcoder\n"); + + /* Workaround: clear timing override bit. */ + val = I915_READ(_TRANSA_CHICKEN2); + val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; + I915_WRITE(_TRANSA_CHICKEN2, val); } /** @@ -1735,9 +1814,17 @@ static void intel_disable_transcoder(struct drm_i915_private *dev_priv, static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool pch_port) { + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); + enum transcoder pch_transcoder; int reg; u32 val; + if (IS_HASWELL(dev_priv->dev)) + pch_transcoder = TRANSCODER_A; + else + pch_transcoder = pipe; + /* * A pipe without a PLL won't actually be able to drive bits from * a plane. On ILK+ the pipe PLLs are integrated, so we don't @@ -1748,13 +1835,13 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, else { if (pch_port) { /* if driving the PCH, we need FDI enabled */ - assert_fdi_rx_pll_enabled(dev_priv, pipe); - assert_fdi_tx_pll_enabled(dev_priv, pipe); + assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder); + assert_fdi_tx_pll_enabled(dev_priv, cpu_transcoder); } /* FIXME: assert CPU port conditions for SNB+ */ } - reg = PIPECONF(pipe); + reg = PIPECONF(cpu_transcoder); val = I915_READ(reg); if (val & PIPECONF_ENABLE) return; @@ -1778,6 +1865,8 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, static void intel_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) { + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); int reg; u32 val; @@ -1791,7 +1880,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) return; - reg = PIPECONF(pipe); + reg = PIPECONF(cpu_transcoder); val = I915_READ(reg); if ((val & PIPECONF_ENABLE) == 0) return; @@ -1807,8 +1896,10 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane) { - I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); - I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); + if (dev_priv->info->gen >= 4) + I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); + else + I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); } /** @@ -1926,9 +2017,9 @@ void intel_unpin_fb_obj(struct drm_i915_gem_object *obj) /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel * is assumed to be a power-of-two. */ -static unsigned long gen4_compute_dspaddr_offset_xtiled(int *x, int *y, - unsigned int bpp, - unsigned int pitch) +unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y, + unsigned int bpp, + unsigned int pitch) { int tile_rows, tiles; @@ -1969,24 +2060,38 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, dspcntr = I915_READ(reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (fb->bits_per_pixel) { - case 8: + switch (fb->pixel_format) { + case DRM_FORMAT_C8: dspcntr |= DISPPLANE_8BPP; break; - case 16: - if (fb->depth == 15) - dspcntr |= DISPPLANE_15_16BPP; - else - dspcntr |= DISPPLANE_16BPP; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: + dspcntr |= DISPPLANE_BGRX555; break; - case 24: - case 32: - dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + case DRM_FORMAT_RGB565: + dspcntr |= DISPPLANE_BGRX565; + break; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + dspcntr |= DISPPLANE_BGRX888; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + dspcntr |= DISPPLANE_RGBX888; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + dspcntr |= DISPPLANE_BGRX101010; + break; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + dspcntr |= DISPPLANE_RGBX101010; break; default: - DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel); + DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); return -EINVAL; } + if (INTEL_INFO(dev)->gen >= 4) { if (obj->tiling_mode != I915_TILING_NONE) dspcntr |= DISPPLANE_TILED; @@ -2000,9 +2105,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (INTEL_INFO(dev)->gen >= 4) { intel_crtc->dspaddr_offset = - gen4_compute_dspaddr_offset_xtiled(&x, &y, - fb->bits_per_pixel / 8, - fb->pitches[0]); + intel_gen4_compute_offset_xtiled(&x, &y, + fb->bits_per_pixel / 8, + fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; } else { intel_crtc->dspaddr_offset = linear_offset; @@ -2053,27 +2158,31 @@ static int ironlake_update_plane(struct drm_crtc *crtc, dspcntr = I915_READ(reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (fb->bits_per_pixel) { - case 8: + switch (fb->pixel_format) { + case DRM_FORMAT_C8: dspcntr |= DISPPLANE_8BPP; break; - case 16: - if (fb->depth != 16) - return -EINVAL; - - dspcntr |= DISPPLANE_16BPP; + case DRM_FORMAT_RGB565: + dspcntr |= DISPPLANE_BGRX565; break; - case 24: - case 32: - if (fb->depth == 24) - dspcntr |= DISPPLANE_32BPP_NO_ALPHA; - else if (fb->depth == 30) - dspcntr |= DISPPLANE_32BPP_30BIT_NO_ALPHA; - else - return -EINVAL; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + dspcntr |= DISPPLANE_BGRX888; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + dspcntr |= DISPPLANE_RGBX888; + break; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + dspcntr |= DISPPLANE_BGRX101010; + break; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + dspcntr |= DISPPLANE_RGBX101010; break; default: - DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel); + DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format); return -EINVAL; } @@ -2089,9 +2198,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); intel_crtc->dspaddr_offset = - gen4_compute_dspaddr_offset_xtiled(&x, &y, - fb->bits_per_pixel / 8, - fb->pitches[0]); + intel_gen4_compute_offset_xtiled(&x, &y, + fb->bits_per_pixel / 8, + fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n", @@ -2099,8 +2208,12 @@ static int ironlake_update_plane(struct drm_crtc *crtc, I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); I915_MODIFY_DISPBASE(DSPSURF(plane), obj->gtt_offset + intel_crtc->dspaddr_offset); - I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); - I915_WRITE(DSPLINOFF(plane), linear_offset); + if (IS_HASWELL(dev)) { + I915_WRITE(DSPOFFSET(plane), (y << 16) | x); + } else { + I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); + I915_WRITE(DSPLINOFF(plane), linear_offset); + } POSTING_READ(reg); return 0; @@ -2148,13 +2261,39 @@ intel_finish_fb(struct drm_framebuffer *old_fb) return ret; } +static void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_master_private *master_priv; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + if (!dev->primary->master) + return; + + master_priv = dev->primary->master->driver_priv; + if (!master_priv->sarea_priv) + return; + + switch (intel_crtc->pipe) { + case 0: + master_priv->sarea_priv->pipeA_x = x; + master_priv->sarea_priv->pipeA_y = y; + break; + case 1: + master_priv->sarea_priv->pipeB_x = x; + master_priv->sarea_priv->pipeB_y = y; + break; + default: + break; + } +} + static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_framebuffer *old_fb; int ret; @@ -2206,20 +2345,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); - if (!dev->primary->master) - return 0; - - master_priv = dev->primary->master->driver_priv; - if (!master_priv->sarea_priv) - return 0; - - if (intel_crtc->pipe) { - master_priv->sarea_priv->pipeB_x = x; - master_priv->sarea_priv->pipeB_y = y; - } else { - master_priv->sarea_priv->pipeA_x = x; - master_priv->sarea_priv->pipeA_y = y; - } + intel_crtc_update_sarea_pos(crtc, x, y); return 0; } @@ -2302,16 +2428,27 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } -static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe) +static void ivb_modeset_global_resources(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 flags = I915_READ(SOUTH_CHICKEN1); + struct intel_crtc *pipe_B_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); + struct intel_crtc *pipe_C_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]); + uint32_t temp; - flags |= FDI_PHASE_SYNC_OVR(pipe); - I915_WRITE(SOUTH_CHICKEN1, flags); /* once to unlock... */ - flags |= FDI_PHASE_SYNC_EN(pipe); - I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to enable */ - POSTING_READ(SOUTH_CHICKEN1); + /* When everything is off disable fdi C so that we could enable fdi B + * with all lanes. XXX: This misses the case where a pipe is not using + * any pch resources and so doesn't need any fdi lanes. */ + if (!pipe_B_crtc->base.enabled && !pipe_C_crtc->base.enabled) { + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); + + temp = I915_READ(SOUTH_CHICKEN1); + temp &= ~FDI_BC_BIFURCATION_SELECT; + DRM_DEBUG_KMS("disabling fdi C rx\n"); + I915_WRITE(SOUTH_CHICKEN1, temp); + } } /* The FDI link training functions for ILK/Ibexpeak. */ @@ -2357,11 +2494,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) udelay(150); /* Ironlake workaround, enable clock pointer after FDI enable*/ - if (HAS_PCH_IBX(dev)) { - I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); - I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR | - FDI_RX_PHASE_SYNC_POINTER_EN); - } + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR | + FDI_RX_PHASE_SYNC_POINTER_EN); reg = FDI_RX_IIR(pipe); for (tries = 0; tries < 5; tries++) { @@ -2450,6 +2585,9 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; I915_WRITE(reg, temp | FDI_TX_ENABLE); + I915_WRITE(FDI_RX_MISC(pipe), + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + reg = FDI_RX_CTL(pipe); temp = I915_READ(reg); if (HAS_PCH_CPT(dev)) { @@ -2464,9 +2602,6 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); - if (HAS_PCH_CPT(dev)) - cpt_phase_pointer_enable(dev, pipe); - for (i = 0; i < 4; i++) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2570,6 +2705,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); + DRM_DEBUG_KMS("FDI_RX_IIR before link train 0x%x\n", + I915_READ(FDI_RX_IIR(pipe))); + /* enable CPU FDI TX and PCH FDI RX */ reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2582,6 +2720,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) temp |= FDI_COMPOSITE_SYNC; I915_WRITE(reg, temp | FDI_TX_ENABLE); + I915_WRITE(FDI_RX_MISC(pipe), + FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + reg = FDI_RX_CTL(pipe); temp = I915_READ(reg); temp &= ~FDI_LINK_TRAIN_AUTO; @@ -2593,9 +2734,6 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); - if (HAS_PCH_CPT(dev)) - cpt_phase_pointer_enable(dev, pipe); - for (i = 0; i < 4; i++) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2613,7 +2751,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) if (temp & FDI_RX_BIT_LOCK || (I915_READ(reg) & FDI_RX_BIT_LOCK)) { I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); - DRM_DEBUG_KMS("FDI train 1 done.\n"); + DRM_DEBUG_KMS("FDI train 1 done, level %i.\n", i); break; } } @@ -2654,7 +2792,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) if (temp & FDI_RX_SYMBOL_LOCK) { I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); - DRM_DEBUG_KMS("FDI train 2 done.\n"); + DRM_DEBUG_KMS("FDI train 2 done, level %i.\n", i); break; } } @@ -2671,9 +2809,6 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) int pipe = intel_crtc->pipe; u32 reg, temp; - /* Write the TU size bits so error detection works */ - I915_WRITE(FDI_RX_TUSIZE1(pipe), - I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK); /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ reg = FDI_RX_CTL(pipe); @@ -2737,17 +2872,6 @@ static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc) udelay(100); } -static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 flags = I915_READ(SOUTH_CHICKEN1); - - flags &= ~(FDI_PHASE_SYNC_EN(pipe)); - I915_WRITE(SOUTH_CHICKEN1, flags); /* once to disable... */ - flags &= ~(FDI_PHASE_SYNC_OVR(pipe)); - I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to lock */ - POSTING_READ(SOUTH_CHICKEN1); -} static void ironlake_fdi_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2774,11 +2898,6 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) /* Ironlake workaround, disable clock pointer after downing FDI */ if (HAS_PCH_IBX(dev)) { I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); - I915_WRITE(FDI_RX_CHICKEN(pipe), - I915_READ(FDI_RX_CHICKEN(pipe) & - ~FDI_RX_PHASE_SYNC_POINTER_EN)); - } else if (HAS_PCH_CPT(dev)) { - cpt_phase_pointer_disable(dev, pipe); } /* still set train pattern 1 */ @@ -2839,7 +2958,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -static bool intel_crtc_driving_pch(struct drm_crtc *crtc) +static bool ironlake_crtc_driving_pch(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct intel_encoder *intel_encoder; @@ -2849,23 +2968,6 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc) * must be driven by its own crtc; no sharing is possible. */ for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - - /* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell - * CPU handles all others */ - if (IS_HASWELL(dev)) { - /* It is still unclear how this will work on PPT, so throw up a warning */ - WARN_ON(!HAS_PCH_LPT(dev)); - - if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { - DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n"); - return true; - } else { - DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n", - intel_encoder->type); - return false; - } - } - switch (intel_encoder->type) { case INTEL_OUTPUT_EDP: if (!intel_encoder_is_pch_edp(&intel_encoder->base)) @@ -2877,6 +2979,11 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc) 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) { @@ -2892,8 +2999,9 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) /* Disable SSCCTL */ intel_sbi_write(dev_priv, SBI_SSCCTL6, - intel_sbi_read(dev_priv, SBI_SSCCTL6) | - SBI_SSCCTL_DISABLE); + intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK) | + SBI_SSCCTL_DISABLE, + SBI_ICLK); /* 20MHz is a corner case which is out of range for the 7-bit divisor */ if (crtc->mode.clock == 20000) { @@ -2934,33 +3042,25 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) phaseinc); /* Program SSCDIVINTPHASE6 */ - temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6); + temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK); temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); temp |= SBI_SSCDIVINTPHASE_PROPAGATE; - - intel_sbi_write(dev_priv, - SBI_SSCDIVINTPHASE6, - temp); + intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK); /* Program SSCAUXDIV */ - temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6); + temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK); temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1); temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv); - intel_sbi_write(dev_priv, - SBI_SSCAUXDIV6, - temp); - + intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK); /* Enable modulator and associated divider */ - temp = intel_sbi_read(dev_priv, SBI_SSCCTL6); + temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK); temp &= ~SBI_SSCCTL_DISABLE; - intel_sbi_write(dev_priv, - SBI_SSCCTL6, - temp); + intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK); /* Wait for initialization time */ udelay(24); @@ -2986,15 +3086,24 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) assert_transcoder_disabled(dev_priv, pipe); + /* Write the TU size bits before fdi link training, so that error + * detection works. */ + I915_WRITE(FDI_RX_TUSIZE1(pipe), + I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK); + /* For PCH output, training FDI link */ dev_priv->display.fdi_link_train(crtc); - intel_enable_pch_pll(intel_crtc); + /* XXX: pch pll's can be enabled any time before we enable the PCH + * transcoder, and we actually should do this to not upset any PCH + * transcoder that already use the clock when we share it. + * + * Note that enable_pch_pll tries to do the right thing, but get_pch_pll + * unconditionally resets the pll - we need that to have the right LVDS + * enable sequence. */ + ironlake_enable_pch_pll(intel_crtc); - if (HAS_PCH_LPT(dev)) { - DRM_DEBUG_KMS("LPT detected: programming iCLKIP\n"); - lpt_program_iclkip(crtc); - } else if (HAS_PCH_CPT(dev)) { + if (HAS_PCH_CPT(dev)) { u32 sel; temp = I915_READ(PCH_DPLL_SEL); @@ -3031,8 +3140,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe))); I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe))); - if (!IS_HASWELL(dev)) - intel_fdi_normal_train(crtc); + intel_fdi_normal_train(crtc); /* For PCH DP, enable TRANS_DP_CTL */ if (HAS_PCH_CPT(dev) && @@ -3064,15 +3172,37 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) temp |= TRANS_DP_PORT_SEL_D; break; default: - DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n"); - temp |= TRANS_DP_PORT_SEL_B; - break; + BUG(); } I915_WRITE(reg, temp); } - intel_enable_transcoder(dev_priv, pipe); + ironlake_enable_pch_transcoder(dev_priv, pipe); +} + +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; + + assert_transcoder_disabled(dev_priv, TRANSCODER_A); + + lpt_program_iclkip(crtc); + + /* Set transcoder timing. */ + I915_WRITE(_TRANS_HTOTAL_A, I915_READ(HTOTAL(cpu_transcoder))); + I915_WRITE(_TRANS_HBLANK_A, I915_READ(HBLANK(cpu_transcoder))); + I915_WRITE(_TRANS_HSYNC_A, I915_READ(HSYNC(cpu_transcoder))); + + I915_WRITE(_TRANS_VTOTAL_A, I915_READ(VTOTAL(cpu_transcoder))); + I915_WRITE(_TRANS_VBLANK_A, I915_READ(VBLANK(cpu_transcoder))); + I915_WRITE(_TRANS_VSYNC_A, I915_READ(VSYNC(cpu_transcoder))); + I915_WRITE(_TRANS_VSYNCSHIFT_A, I915_READ(VSYNCSHIFT(cpu_transcoder))); + + lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); } static void intel_put_pch_pll(struct intel_crtc *intel_crtc) @@ -3165,16 +3295,12 @@ prepare: /* separate function? */ void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - int dslreg = PIPEDSL(pipe), tc2reg = TRANS_CHICKEN2(pipe); + int dslreg = PIPEDSL(pipe); u32 temp; temp = I915_READ(dslreg); udelay(500); if (wait_for(I915_READ(dslreg) != temp, 5)) { - /* Without this, mode sets may fail silently on FDI */ - I915_WRITE(tc2reg, TRANS_AUTOTRAIN_GEN_STALL_DIS); - udelay(250); - I915_WRITE(tc2reg, 0); if (wait_for(I915_READ(dslreg) != temp, 5)) DRM_ERROR("mode set failed: pipe %d stuck\n", pipe); } @@ -3205,9 +3331,12 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); } - is_pch_port = intel_crtc_driving_pch(crtc); + is_pch_port = ironlake_crtc_driving_pch(crtc); if (is_pch_port) { + /* Note: FDI PLL enabling _must_ be done before we enable the + * cpu pipes, hence this is separate from all the other fdi/pch + * enabling. */ ironlake_fdi_pll_enable(intel_crtc); } else { assert_fdi_tx_disabled(dev_priv, pipe); @@ -3220,12 +3349,17 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) /* Enable panel fitting for LVDS */ if (dev_priv->pch_pf_size && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) { + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { /* Force use of hard-coded filter coefficients * as some pre-programmed values are broken, * e.g. x201. */ - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); + if (IS_IVYBRIDGE(dev)) + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | + PF_PIPE_SEL_IVB(pipe)); + else + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); } @@ -3265,6 +3399,83 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_wait_for_vblank(dev, intel_crtc->pipe); } +static void haswell_crtc_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); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + bool is_pch_port; + + WARN_ON(!crtc->enabled); + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + intel_update_watermarks(dev); + + is_pch_port = haswell_crtc_driving_pch(crtc); + + if (is_pch_port) + dev_priv->display.fdi_link_train(crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + + intel_ddi_enable_pipe_clock(intel_crtc); + + /* Enable panel fitting for eDP */ + if (dev_priv->pch_pf_size && + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | + PF_PIPE_SEL_IVB(pipe)); + I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); + I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); + } + + /* + * On ILK+ LUT must be loaded before the pipe is running but with + * clocks enabled + */ + intel_crtc_load_lut(crtc); + + intel_ddi_set_pipe_settings(crtc); + intel_ddi_enable_pipe_func(crtc); + + intel_enable_pipe(dev_priv, pipe, is_pch_port); + intel_enable_plane(dev_priv, plane, pipe); + + if (is_pch_port) + lpt_pch_enable(crtc); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); + + intel_crtc_update_cursor(crtc, true); + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); + + /* + * There seems to be a race in PCH platform hw (at least on some + * outputs) where an enabled pipe still completes any pageflip right + * away (as if the pipe is off) instead of waiting for vblank. As soon + * as the first vblank happend, everything works as expected. Hence just + * wait for one vblank before returning to avoid strange things + * happening. + */ + intel_wait_for_vblank(dev, intel_crtc->pipe); +} + static void ironlake_crtc_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3303,7 +3514,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_disable(crtc); - intel_disable_transcoder(dev_priv, pipe); + ironlake_disable_pch_transcoder(dev_priv, pipe); if (HAS_PCH_CPT(dev)) { /* disable TRANS_DP_CTL */ @@ -3345,12 +3556,78 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } +static void haswell_crtc_disable(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); + 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; + + if (!intel_crtc->active) + return; + + is_pch_port = haswell_crtc_driving_pch(crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->disable(encoder); + + intel_crtc_wait_for_pending_flips(crtc); + drm_vblank_off(dev, pipe); + intel_crtc_update_cursor(crtc, false); + + intel_disable_plane(dev_priv, plane, pipe); + + if (dev_priv->cfb_plane == plane) + intel_disable_fbc(dev); + + intel_disable_pipe(dev_priv, pipe); + + intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); + + /* Disable PF */ + I915_WRITE(PF_CTL(pipe), 0); + I915_WRITE(PF_WIN_SZ(pipe), 0); + + intel_ddi_disable_pipe_clock(intel_crtc); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->post_disable) + encoder->post_disable(encoder); + + if (is_pch_port) { + lpt_disable_pch_transcoder(dev_priv); + intel_ddi_fdi_disable(crtc); + } + + intel_crtc->active = false; + intel_update_watermarks(dev); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); +} + static void ironlake_crtc_off(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); intel_put_pch_pll(intel_crtc); } +static void haswell_crtc_off(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* Stop saying we're using TRANSCODER_EDP because some other CRTC might + * start using it. */ + intel_crtc->cpu_transcoder = intel_crtc->pipe; + + intel_ddi_put_crtc_pll(crtc); +} + static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) { if (!enable && intel_crtc->overlay) { @@ -4061,7 +4338,7 @@ 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 refclk, int num_connectors) + int num_connectors) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4069,9 +4346,19 @@ static void vlv_update_pll(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; u32 dpll, mdiv, pdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; - bool is_hdmi; + bool is_sdvo; + u32 temp; + + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + + dpll = DPLL_VGA_MODE_DIS; + dpll |= DPLL_EXT_BUFFER_ENABLE_VLV; + dpll |= DPLL_REFA_CLK_ENABLE_VLV; + dpll |= DPLL_INTEGRATED_CLOCK_VLV; - is_hdmi = intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); + I915_WRITE(DPLL(pipe), dpll); + POSTING_READ(DPLL(pipe)); bestn = clock->n; bestm1 = clock->m1; @@ -4079,12 +4366,10 @@ static void vlv_update_pll(struct drm_crtc *crtc, bestp1 = clock->p1; bestp2 = clock->p2; - /* Enable DPIO clock input */ - dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | - DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; - I915_WRITE(DPLL(pipe), dpll); - POSTING_READ(DPLL(pipe)); - + /* + * In Valleyview PLL and program lane counter registers are exposed + * through DPIO interface + */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); mdiv |= ((bestn << DPIO_N_SHIFT)); @@ -4095,12 +4380,13 @@ static void vlv_update_pll(struct drm_crtc *crtc, intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000); - pdiv = DPIO_REFSEL_OVERRIDE | (5 << DPIO_PLL_MODESEL_SHIFT) | + pdiv = (1 << DPIO_REFSEL_OVERRIDE) | (5 << DPIO_PLL_MODESEL_SHIFT) | (3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) | - (8 << DPIO_DRIVER_CTL_SHIFT) | (5 << DPIO_CLK_BIAS_CTL_SHIFT); + (7 << DPIO_PLL_REFCLK_SEL_SHIFT) | (8 << DPIO_DRIVER_CTL_SHIFT) | + (5 << DPIO_CLK_BIAS_CTL_SHIFT); intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv); - intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x009f0051); + intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f003b); dpll |= DPLL_VCO_ENABLE; I915_WRITE(DPLL(pipe), dpll); @@ -4108,19 +4394,44 @@ static void vlv_update_pll(struct drm_crtc *crtc, if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) DRM_ERROR("DPLL %d failed to lock\n", pipe); - if (is_hdmi) { - u32 temp = intel_mode_get_pixel_multiplier(adjusted_mode); + 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); + + I915_WRITE(DPLL(pipe), dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(DPLL(pipe)); + udelay(150); + + 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; - - I915_WRITE(DPLL_MD(pipe), temp); - POSTING_READ(DPLL_MD(pipe)); } + I915_WRITE(DPLL_MD(pipe), temp); + POSTING_READ(DPLL_MD(pipe)); - intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x641); /* ??? */ + /* Now program lane control registers */ + if(intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) + || intel_pipe_has_type(crtc, 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)) + { + temp = 0x1000C4; + if(pipe == 1) + temp |= (1 << 21); + intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp); + } } static void i9xx_update_pll(struct drm_crtc *crtc, @@ -4136,6 +4447,8 @@ static void i9xx_update_pll(struct drm_crtc *crtc, u32 dpll; bool is_sdvo; + i9xx_update_pll_dividers(crtc, clock, reduced_clock); + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); @@ -4236,7 +4549,7 @@ static void i9xx_update_pll(struct drm_crtc *crtc, static void i8xx_update_pll(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, - intel_clock_t *clock, + intel_clock_t *clock, intel_clock_t *reduced_clock, int num_connectors) { struct drm_device *dev = crtc->dev; @@ -4245,6 +4558,8 @@ static void i8xx_update_pll(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; u32 dpll; + i9xx_update_pll_dividers(crtc, clock, reduced_clock); + dpll = DPLL_VGA_MODE_DIS; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { @@ -4294,6 +4609,64 @@ static void i8xx_update_pll(struct drm_crtc *crtc, I915_WRITE(DPLL(pipe), dpll); } +static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + 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; + uint32_t vsyncshift; + + if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + /* the chip adds 2 halflines automatically */ + adjusted_mode->crtc_vtotal -= 1; + adjusted_mode->crtc_vblank_end -= 1; + vsyncshift = adjusted_mode->crtc_hsync_start + - adjusted_mode->crtc_htotal / 2; + } else { + vsyncshift = 0; + } + + if (INTEL_INFO(dev)->gen > 3) + I915_WRITE(VSYNCSHIFT(cpu_transcoder), vsyncshift); + + I915_WRITE(HTOTAL(cpu_transcoder), + (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + I915_WRITE(HBLANK(cpu_transcoder), + (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + I915_WRITE(HSYNC(cpu_transcoder), + (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + + I915_WRITE(VTOTAL(cpu_transcoder), + (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + I915_WRITE(VBLANK(cpu_transcoder), + (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + I915_WRITE(VSYNC(cpu_transcoder), + (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + + /* Workaround: when the EDP input selection is B, the VTOTAL_B must be + * programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is + * documented on the DDI_FUNC_CTL register description, EDP Input Select + * bits. */ + if (IS_HASWELL(dev) && cpu_transcoder == TRANSCODER_EDP && + (pipe == PIPE_B || pipe == PIPE_C)) + I915_WRITE(VTOTAL(pipe), I915_READ(VTOTAL(cpu_transcoder))); + + /* pipesrc controls the size that is scaled from, which should + * always be the user's requested size. + */ + I915_WRITE(PIPESRC(pipe), + ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); +} + static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4307,7 +4680,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dspcntr, pipeconf, vsyncshift; + u32 dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_lvds = false, is_tv = false, is_dp = false; struct intel_encoder *encoder; @@ -4371,14 +4744,14 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, if (is_sdvo && is_tv) i9xx_adjust_sdvo_tv_clock(adjusted_mode, &clock); - i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ? - &reduced_clock : NULL); - if (IS_GEN2(dev)) - i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors); + i8xx_update_pll(crtc, adjusted_mode, &clock, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); else if (IS_VALLEYVIEW(dev)) - vlv_update_pll(crtc, mode,adjusted_mode, &clock, NULL, - refclk, num_connectors); + vlv_update_pll(crtc, mode, adjusted_mode, &clock, + has_reduced_clock ? &reduced_clock : NULL, + num_connectors); else i9xx_update_pll(crtc, mode, adjusted_mode, &clock, has_reduced_clock ? &reduced_clock : NULL, @@ -4419,6 +4792,14 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, } } + if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { + if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { + pipeconf |= PIPECONF_BPP_6 | + PIPECONF_ENABLE | + I965_PIPECONF_ACTIVE; + } + } + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); @@ -4434,40 +4815,12 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPECONF_INTERLACE_MASK; if (!IS_GEN2(dev) && - adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; - /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_end -= 1; - vsyncshift = adjusted_mode->crtc_hsync_start - - adjusted_mode->crtc_htotal/2; - } else { + else pipeconf |= PIPECONF_PROGRESSIVE; - vsyncshift = 0; - } - if (!IS_GEN3(dev)) - I915_WRITE(VSYNCSHIFT(pipe), vsyncshift); - - I915_WRITE(HTOTAL(pipe), - (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(HBLANK(pipe), - (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(HSYNC(pipe), - (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - - I915_WRITE(VTOTAL(pipe), - (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(VBLANK(pipe), - (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(VSYNC(pipe), - (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); + intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); /* pipesrc and dspsize control the size that is scaled from, * which should always be the user's requested size. @@ -4476,8 +4829,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); I915_WRITE(DSPPOS(plane), 0); - I915_WRITE(PIPESRC(pipe), - ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); I915_WRITE(PIPECONF(pipe), pipeconf); POSTING_READ(PIPECONF(pipe)); @@ -4495,10 +4846,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, return ret; } -/* - * Initialize reference clocks when the driver loads - */ -void ironlake_init_pch_refclk(struct drm_device *dev) +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; @@ -4612,6 +4960,182 @@ void ironlake_init_pch_refclk(struct drm_device *dev) } } +/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */ +static void lpt_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; + bool has_vga = false; + bool is_sdv = false; + u32 tmp; + + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { + switch (encoder->type) { + case INTEL_OUTPUT_ANALOG: + has_vga = true; + break; + } + } + + if (!has_vga) + return; + + /* XXX: Rip out SDV support once Haswell ships for real. */ + if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00) + is_sdv = true; + + tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK); + tmp &= ~SBI_SSCCTL_DISABLE; + tmp |= SBI_SSCCTL_PATHALT; + intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK); + + udelay(24); + + tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK); + tmp &= ~SBI_SSCCTL_PATHALT; + intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK); + + if (!is_sdv) { + tmp = I915_READ(SOUTH_CHICKEN2); + tmp |= FDI_MPHY_IOSFSB_RESET_CTL; + I915_WRITE(SOUTH_CHICKEN2, tmp); + + if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) & + FDI_MPHY_IOSFSB_RESET_STATUS, 100)) + DRM_ERROR("FDI mPHY reset assert timeout\n"); + + tmp = I915_READ(SOUTH_CHICKEN2); + tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL; + I915_WRITE(SOUTH_CHICKEN2, tmp); + + if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) & + FDI_MPHY_IOSFSB_RESET_STATUS) == 0, + 100)) + DRM_ERROR("FDI mPHY reset de-assert timeout\n"); + } + + tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY); + tmp &= ~(0xFF << 24); + 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; + intel_sbi_write(dev_priv, 0x800C, tmp, SBI_MPHY); + } + + tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY); + tmp |= (1 << 11); + intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY); + tmp |= (1 << 11); + intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY); + + if (is_sdv) { + tmp = intel_sbi_read(dev_priv, 0x2038, SBI_MPHY); + tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16); + intel_sbi_write(dev_priv, 0x2038, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2138, SBI_MPHY); + tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16); + intel_sbi_write(dev_priv, 0x2138, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x203C, SBI_MPHY); + tmp |= (0x3F << 8); + intel_sbi_write(dev_priv, 0x203C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x213C, SBI_MPHY); + tmp |= (0x3F << 8); + intel_sbi_write(dev_priv, 0x213C, tmp, SBI_MPHY); + } + + tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY); + tmp |= (1 << 24) | (1 << 21) | (1 << 18); + intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY); + tmp |= (1 << 24) | (1 << 21) | (1 << 18); + intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY); + + if (!is_sdv) { + tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY); + tmp &= ~(7 << 13); + tmp |= (5 << 13); + intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY); + tmp &= ~(7 << 13); + tmp |= (5 << 13); + intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY); + } + + tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY); + tmp &= ~0xFF; + tmp |= 0x1C; + intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY); + tmp &= ~0xFF; + tmp |= 0x1C; + intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY); + tmp &= ~(0xFF << 16); + tmp |= (0x1C << 16); + intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY); + tmp &= ~(0xFF << 16); + tmp |= (0x1C << 16); + intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY); + + if (!is_sdv) { + tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY); + tmp |= (1 << 27); + intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY); + tmp |= (1 << 27); + intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY); + tmp &= ~(0xF << 28); + tmp |= (4 << 28); + intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY); + + tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY); + tmp &= ~(0xF << 28); + tmp |= (4 << 28); + intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY); + } + + /* ULT uses SBI_GEN0, but ULT doesn't have VGA, so we don't care. */ + tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK); + tmp |= SBI_DBUFF0_ENABLE; + intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK); +} + +/* + * Initialize reference clocks when the driver loads + */ +void intel_init_pch_refclk(struct drm_device *dev) +{ + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + ironlake_init_pch_refclk(dev); + else if (HAS_PCH_LPT(dev)) + lpt_init_pch_refclk(dev); +} + static int ironlake_get_refclk(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -4668,8 +5192,8 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, val |= PIPE_12BPC; break; default: - val |= PIPE_8BPC; - break; + /* Case prevented by intel_choose_pipe_bpp_dither. */ + BUG(); } val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); @@ -4686,6 +5210,31 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, POSTING_READ(PIPECONF(pipe)); } +static void haswell_set_pipeconf(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode, + bool dither) +{ + 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; + uint32_t val; + + val = I915_READ(PIPECONF(cpu_transcoder)); + + val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); + if (dither) + val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); + + val &= ~PIPECONF_INTERLACE_MASK_HSW; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + val |= PIPECONF_INTERLACED_ILK; + else + val |= PIPECONF_PROGRESSIVE; + + I915_WRITE(PIPECONF(cpu_transcoder), val); + POSTING_READ(PIPECONF(cpu_transcoder)); +} + static bool ironlake_compute_clocks(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, intel_clock_t *clock, @@ -4749,74 +5298,126 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, return true; } -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) +static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t temp; + + temp = I915_READ(SOUTH_CHICKEN1); + if (temp & FDI_BC_BIFURCATION_SELECT) + return; + + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); + + temp |= FDI_BC_BIFURCATION_SELECT; + DRM_DEBUG_KMS("enabling fdi C rx\n"); + I915_WRITE(SOUTH_CHICKEN1, temp); + POSTING_READ(SOUTH_CHICKEN1); +} + +static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *pipe_B_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); + + DRM_DEBUG_KMS("checking fdi config on pipe %i, lanes %i\n", + intel_crtc->pipe, intel_crtc->fdi_lanes); + if (intel_crtc->fdi_lanes > 4) { + DRM_DEBUG_KMS("invalid fdi lane config on pipe %i: %i lanes\n", + intel_crtc->pipe, intel_crtc->fdi_lanes); + /* Clamp lanes to avoid programming the hw with bogus values. */ + intel_crtc->fdi_lanes = 4; + + return false; + } + + if (dev_priv->num_pipe == 2) + return true; + + switch (intel_crtc->pipe) { + case PIPE_A: + return true; + case PIPE_B: + if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && + intel_crtc->fdi_lanes > 2) { + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n", + intel_crtc->pipe, intel_crtc->fdi_lanes); + /* Clamp lanes to avoid programming the hw with bogus values. */ + intel_crtc->fdi_lanes = 2; + + return false; + } + + if (intel_crtc->fdi_lanes > 2) + WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); + else + cpt_enable_fdi_bc_bifurcation(dev); + + return true; + case PIPE_C: + if (!pipe_B_crtc->base.enabled || pipe_B_crtc->fdi_lanes <= 2) { + if (intel_crtc->fdi_lanes > 2) { + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n", + intel_crtc->pipe, intel_crtc->fdi_lanes); + /* Clamp lanes to avoid programming the hw with bogus values. */ + intel_crtc->fdi_lanes = 2; + + return false; + } + } else { + DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n"); + return false; + } + + cpt_enable_fdi_bc_bifurcation(dev); + + return true; + default: + BUG(); + } +} + +int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp) +{ + /* + * Account for spread spectrum to avoid + * oversubscribing the link. Max center spread + * is 2.5%; use 5% for safety's sake. + */ + u32 bps = target_clock * bpp * 21 / 20; + 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) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - 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, is_sdvo = false; - bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *encoder, *edp_encoder = NULL; - int ret; + enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + struct intel_encoder *intel_encoder, *edp_encoder = NULL; struct fdi_m_n m_n = {0}; - u32 temp; - int target_clock, pixel_multiplier, lane, link_bw, factor; - unsigned int pipe_bpp; - bool dither; - bool is_cpu_edp = false, is_pch_edp = false; + int target_clock, pixel_multiplier, lane, link_bw; + bool is_dp = false, is_cpu_edp = false; - for_each_encoder_on_crtc(dev, crtc, encoder) { - switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; - case INTEL_OUTPUT_SDVO: - case INTEL_OUTPUT_HDMI: - is_sdvo = true; - if (encoder->needs_tv_clock) - is_tv = true; - break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; - case INTEL_OUTPUT_ANALOG: - is_crt = true; - break; + 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(&encoder->base)) - is_pch_edp = true; - else + if (!intel_encoder_is_pch_edp(&intel_encoder->base)) is_cpu_edp = true; - edp_encoder = encoder; + edp_encoder = intel_encoder; break; } - - num_connectors++; } - 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; - } - - /* Ensure that the cursor is valid for the new mode before changing... */ - intel_crtc_update_cursor(crtc, true); - /* FDI link */ pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); lane = 0; @@ -4843,29 +5444,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else target_clock = adjusted_mode->clock; - /* determine panel color depth */ - dither = intel_choose_pipe_bpp_dither(crtc, fb, &pipe_bpp, - adjusted_mode); - if (is_lvds && dev_priv->lvds_dither) - dither = true; - - if (pipe_bpp != 18 && pipe_bpp != 24 && pipe_bpp != 30 && - pipe_bpp != 36) { - WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n", - pipe_bpp); - pipe_bpp = 24; - } - intel_crtc->bpp = pipe_bpp; - - if (!lane) { - /* - * Account for spread spectrum to avoid - * oversubscribing the link. Max center spread - * is 2.5%; use 5% for safety's sake. - */ - u32 bps = target_clock * intel_crtc->bpp * 21 / 20; - lane = bps / (link_bw * 8) + 1; - } + if (!lane) + lane = ironlake_get_lanes_required(target_clock, link_bw, + intel_crtc->bpp); intel_crtc->fdi_lanes = lane; @@ -4874,10 +5455,51 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n); - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; + 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); +} + +static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, + struct drm_display_mode *adjusted_mode, + intel_clock_t *clock, u32 fp) +{ + 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; + 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) { + case INTEL_OUTPUT_LVDS: + is_lvds = true; + break; + case INTEL_OUTPUT_SDVO: + case INTEL_OUTPUT_HDMI: + is_sdvo = true; + if (intel_encoder->needs_tv_clock) + is_tv = true; + break; + 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++; + } /* Enable autotuning of the PLL clock (if permissible) */ factor = 21; @@ -4889,7 +5511,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock.m < factor * clock.n) + if (clock->m < factor * clock->n) fp |= FP_CB_TUNE; dpll = 0; @@ -4899,7 +5521,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; if (is_sdvo) { - int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); + pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); if (pixel_multiplier > 1) { dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } @@ -4909,11 +5531,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; /* also FPA1 */ - dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; - switch (clock.p2) { + switch (clock->p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; break; @@ -4939,15 +5561,79 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else dpll |= PLL_REF_INPUT_DREFCLK; + return dpll; +} + +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); + 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; + struct intel_encoder *encoder; + u32 temp; + int ret; + bool dither, fdi_config_ok; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + 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++; + } + + WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), + "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); + + 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; + } + + /* 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); + if (is_lvds && dev_priv->lvds_dither) + dither = true; + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp); + 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 on - * pre-Haswell/LPT generation */ - if (HAS_PCH_LPT(dev)) { - DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n", - pipe); - } else if (!is_cpu_edp) { + /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ + if (!is_cpu_edp) { struct intel_pch_pll *pll; pll = intel_get_pch_pll(intel_crtc, dpll, fp); @@ -5033,47 +5719,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } } - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { - /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_end -= 1; - I915_WRITE(VSYNCSHIFT(pipe), - adjusted_mode->crtc_hsync_start - - adjusted_mode->crtc_htotal/2); - } else { - I915_WRITE(VSYNCSHIFT(pipe), 0); - } - - I915_WRITE(HTOTAL(pipe), - (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(HBLANK(pipe), - (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(HSYNC(pipe), - (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - - I915_WRITE(VTOTAL(pipe), - (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(VBLANK(pipe), - (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(VSYNC(pipe), - (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); + intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); - /* pipesrc controls the size that is scaled from, which should - * always be the user's requested size. - */ - I915_WRITE(PIPESRC(pipe), - ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + /* 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); - 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); + fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); if (is_cpu_edp) ironlake_set_pll_edp(crtc, adjusted_mode->clock); @@ -5092,6 +5744,217 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_update_linetime_watermarks(dev, pipe, adjusted_mode); + return fdi_config_ok ? ret : -EINVAL; +} + +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); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int num_connectors = 0; + intel_clock_t clock, reduced_clock; + u32 dpll = 0, fp = 0, fp2 = 0; + bool ok, has_reduced_clock = false; + bool is_lvds = false, is_dp = false, is_cpu_edp = false; + struct intel_encoder *encoder; + u32 temp; + int ret; + bool dither; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + switch (encoder->type) { + 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++; + } + + if (is_cpu_edp) + intel_crtc->cpu_transcoder = TRANSCODER_EDP; + else + intel_crtc->cpu_transcoder = pipe; + + /* We are not sure yet this won't happen. */ + WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", + INTEL_PCH_TYPE(dev)); + + 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)) & + (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE)); + + WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE); + + if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) + return -EINVAL; + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + 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; + } + } + + /* 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); + if (is_lvds && dev_priv->lvds_dither) + dither = true; + + DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); + drm_mode_debug_printmodeline(mode); + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, + fp); + + /* CPU eDP is the only output that doesn't need a PCH PLL of its + * own on pre-Haswell/LPT generation */ + if (!is_cpu_edp) { + struct intel_pch_pll *pll; + + pll = intel_get_pch_pll(intel_crtc, dpll, fp); + if (pll == NULL) { + DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", + pipe); + return -EINVAL; + } + } else + intel_put_pch_pll(intel_crtc); + + /* The LVDS pin pair needs to be on before the DPLLs are + * enabled. This is an exception to the general rule that + * mode_set doesn't turn things on. + */ + if (is_lvds) { + temp = I915_READ(PCH_LVDS); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + if (HAS_PCH_CPT(dev)) { + temp &= ~PORT_TRANS_SEL_MASK; + temp |= PORT_TRANS_SEL_CPT(pipe); + } else { + if (pipe == 1) + temp |= LVDS_PIPEB_SELECT; + else + temp &= ~LVDS_PIPEB_SELECT; + } + + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether + * we're going to set the DPLLs for dual-channel mode or + * not. + */ + if (clock.p2 == 7) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + temp &= ~(LVDS_B0B3_POWER_UP | + LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode + * (LVDS_A3_POWER_UP) appropriately here, but we need to + * look more thoroughly into how panels behave in the + * two modes. + */ + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + temp |= LVDS_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + temp |= LVDS_VSYNC_POLARITY; + I915_WRITE(PCH_LVDS, temp); + } + } + + if (is_dp && !is_cpu_edp) { + intel_dp_set_m_n(crtc, mode, adjusted_mode); + } else { + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + /* For non-DP output, clear any trans DP clock recovery + * setting.*/ + I915_WRITE(TRANSDATA_M1(pipe), 0); + I915_WRITE(TRANSDATA_N1(pipe), 0); + I915_WRITE(TRANSDPLINK_M1(pipe), 0); + I915_WRITE(TRANSDPLINK_N1(pipe), 0); + } + } + + intel_crtc->lowfreq_avail = false; + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + if (intel_crtc->pch_pll) { + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(intel_crtc->pch_pll->pll_reg); + udelay(150); + + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + } + + if (intel_crtc->pch_pll) { + if (is_lvds && has_reduced_clock && i915_powersave) { + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); + intel_crtc->lowfreq_avail = true; + } else { + I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); + } + } + } + + intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); + + if (!is_dp || is_cpu_edp) + ironlake_set_m_n(crtc, mode, adjusted_mode); + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + if (is_cpu_edp) + ironlake_set_pll_edp(crtc, adjusted_mode->clock); + + haswell_set_pipeconf(crtc, adjusted_mode, dither); + + /* Set up the display plane register */ + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); + POSTING_READ(DSPCNTR(plane)); + + ret = intel_pipe_set_base(crtc, x, y, fb); + + intel_update_watermarks(dev); + + intel_update_linetime_watermarks(dev, pipe, adjusted_mode); + return ret; } @@ -5103,6 +5966,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_encoder_helper_funcs *encoder_funcs; + struct intel_encoder *encoder; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int ret; @@ -5113,7 +5978,19 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, x, y, fb); drm_vblank_post_modeset(dev, pipe); - return ret; + if (ret != 0) + return ret; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", + 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); + } + + return 0; } static bool intel_eld_uptodate(struct drm_connector *connector, @@ -5749,7 +6626,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev, int depth, int bpp) { struct drm_i915_gem_object *obj; - struct drm_mode_fb_cmd2 mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd = { 0 }; obj = i915_gem_alloc_object(dev, intel_framebuffer_size_for_mode(mode, bpp)); @@ -5879,24 +6756,19 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); - goto fail; + return false; } if (!intel_set_mode(crtc, mode, 0, 0, fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); - goto fail; + return false; } /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev, intel_crtc->pipe); - return true; -fail: - connector->encoder = NULL; - encoder->crtc = NULL; - return false; } void intel_release_load_detect_pipe(struct drm_connector *connector, @@ -6021,12 +6893,12 @@ 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); - int pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; struct drm_display_mode *mode; - int htot = I915_READ(HTOTAL(pipe)); - int hsync = I915_READ(HSYNC(pipe)); - int vtot = I915_READ(VTOTAL(pipe)); - int vsync = I915_READ(VSYNC(pipe)); + int htot = I915_READ(HTOTAL(cpu_transcoder)); + int hsync = I915_READ(HSYNC(cpu_transcoder)); + int vtot = I915_READ(VTOTAL(cpu_transcoder)); + int vsync = I915_READ(VSYNC(cpu_transcoder)); mode = kzalloc(sizeof(*mode), GFP_KERNEL); if (!mode) @@ -6183,14 +7055,19 @@ static void intel_unpin_work_fn(struct work_struct *__work) { struct intel_unpin_work *work = container_of(__work, struct intel_unpin_work, work); + struct drm_device *dev = work->crtc->dev; - mutex_lock(&work->dev->struct_mutex); + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(work->old_fb_obj); drm_gem_object_unreference(&work->pending_flip_obj->base); drm_gem_object_unreference(&work->old_fb_obj->base); - intel_update_fbc(work->dev); - mutex_unlock(&work->dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); + + BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0); + atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count); + kfree(work); } @@ -6201,8 +7078,6 @@ static void do_intel_finish_page_flip(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; struct drm_i915_gem_object *obj; - struct drm_pending_vblank_event *e; - struct timeval tvbl; unsigned long flags; /* Ignore early vblank irqs */ @@ -6211,24 +7086,22 @@ static void do_intel_finish_page_flip(struct drm_device *dev, spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; - if (work == NULL || !work->pending) { + + /* Ensure we don't miss a work->pending update ... */ + smp_rmb(); + + if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { spin_unlock_irqrestore(&dev->event_lock, flags); return; } - intel_crtc->unpin_work = NULL; - - if (work->event) { - e = work->event; - e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl); + /* and that the unpin work is consistent wrt ->pending. */ + smp_rmb(); - e->event.tv_sec = tvbl.tv_sec; - e->event.tv_usec = tvbl.tv_usec; + intel_crtc->unpin_work = NULL; - list_add_tail(&e->base.link, - &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); - } + if (work->event) + drm_send_vblank_event(dev, intel_crtc->pipe, work->event); drm_vblank_put(dev, intel_crtc->pipe); @@ -6238,9 +7111,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev, atomic_clear_mask(1 << intel_crtc->plane, &obj->pending_flip.counter); - wake_up(&dev_priv->pending_flip_queue); - schedule_work(&work->work); + + queue_work(dev_priv->wq, &work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); } @@ -6268,16 +7141,25 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]); unsigned long flags; + /* NB: An MMIO update of the plane base pointer will also + * generate a page-flip completion irq, i.e. every modeset + * is also accompanied by a spurious intel_prepare_page_flip(). + */ spin_lock_irqsave(&dev->event_lock, flags); - if (intel_crtc->unpin_work) { - if ((++intel_crtc->unpin_work->pending) > 1) - DRM_ERROR("Prepared flip multiple times\n"); - } else { - DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n"); - } + if (intel_crtc->unpin_work) + atomic_inc_not_zero(&intel_crtc->unpin_work->pending); spin_unlock_irqrestore(&dev->event_lock, flags); } +inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc) +{ + /* Ensure that the work item is consistent when activating it ... */ + smp_wmb(); + atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING); + /* and that it is marked active as soon as the irq could fire. */ + smp_wmb(); +} + static int intel_gen2_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -6311,6 +7193,8 @@ static int intel_gen2_queue_flip(struct drm_device *dev, intel_ring_emit(ring, fb->pitches[0]); intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); intel_ring_emit(ring, 0); /* aux display base address, unused */ + + intel_mark_page_flip_active(intel_crtc); intel_ring_advance(ring); return 0; @@ -6351,6 +7235,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); intel_ring_emit(ring, MI_NOOP); + intel_mark_page_flip_active(intel_crtc); intel_ring_advance(ring); return 0; @@ -6397,6 +7282,8 @@ static int intel_gen4_queue_flip(struct drm_device *dev, pf = 0; pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; intel_ring_emit(ring, pf | pipesrc); + + intel_mark_page_flip_active(intel_crtc); intel_ring_advance(ring); return 0; @@ -6439,6 +7326,8 @@ static int intel_gen6_queue_flip(struct drm_device *dev, pf = 0; pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; intel_ring_emit(ring, pf | pipesrc); + + intel_mark_page_flip_active(intel_crtc); intel_ring_advance(ring); return 0; @@ -6493,6 +7382,8 @@ static int intel_gen7_queue_flip(struct drm_device *dev, intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); intel_ring_emit(ring, (MI_NOOP)); + + intel_mark_page_flip_active(intel_crtc); intel_ring_advance(ring); return 0; @@ -6541,7 +7432,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return -ENOMEM; work->event = event; - work->dev = crtc->dev; + work->crtc = crtc; intel_fb = to_intel_framebuffer(crtc->fb); work->old_fb_obj = intel_fb->obj; INIT_WORK(&work->work, intel_unpin_work_fn); @@ -6566,6 +7457,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; + if (atomic_read(&intel_crtc->unpin_work_count) >= 2) + flush_workqueue(dev_priv->wq); + ret = i915_mutex_lock_interruptible(dev); if (ret) goto cleanup; @@ -6584,6 +7478,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, * the flip occurs and the object is no longer visible. */ atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); + atomic_inc(&intel_crtc->unpin_work_count); ret = dev_priv->display.queue_flip(dev, crtc, fb, obj); if (ret) @@ -6598,6 +7493,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return 0; cleanup_pending: + atomic_dec(&intel_crtc->unpin_work_count); atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); drm_gem_object_unreference(&work->old_fb_obj->base); drm_gem_object_unreference(&obj->base); @@ -6893,7 +7789,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) dev->mode_config.dpms_property; connector->dpms = DRM_MODE_DPMS_ON; - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, dpms_property, DRM_MODE_DPMS_ON); @@ -7015,8 +7911,6 @@ bool intel_set_mode(struct drm_crtc *crtc, 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_encoder_helper_funcs *encoder_funcs; - struct drm_encoder *encoder; struct intel_crtc *intel_crtc; unsigned disable_pipes, prepare_pipes, modeset_pipes; bool ret = true; @@ -7061,6 +7955,9 @@ bool intel_set_mode(struct drm_crtc *crtc, * update the the output configuration. */ intel_modeset_update_state(dev, prepare_pipes); + if (dev_priv->display.modeset_global_resources) + dev_priv->display.modeset_global_resources(dev); + /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ @@ -7070,18 +7967,6 @@ bool intel_set_mode(struct drm_crtc *crtc, x, y, fb); if (!ret) goto done; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - - if (encoder->crtc != &intel_crtc->base) - continue; - - DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", - encoder->base.id, drm_get_encoder_name(encoder), - mode->base.id, mode->name); - encoder_funcs = encoder->helper_private; - encoder_funcs->mode_set(encoder, mode, adjusted_mode); - } } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ @@ -7420,6 +8305,12 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .page_flip = intel_crtc_page_flip, }; +static void intel_cpu_pll_init(struct drm_device *dev) +{ + if (IS_HASWELL(dev)) + intel_ddi_pll_init(dev); +} + static void intel_pch_pll_init(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -7459,6 +8350,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; if (IS_MOBILE(dev) && IS_GEN3(dev)) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; @@ -7551,17 +8443,9 @@ static void intel_setup_outputs(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, 0); } - if (HAS_PCH_SPLIT(dev)) { - dpd_is_edp = intel_dpd_is_edp(dev); - - if (has_edp_a(dev)) - intel_dp_init(dev, DP_A, PORT_A); - - if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_D, PORT_D); - } - - intel_crt_init(dev); + if (!(IS_HASWELL(dev) && + (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) + intel_crt_init(dev); if (IS_HASWELL(dev)) { int found; @@ -7584,6 +8468,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_ddi_init(dev, PORT_D); } else if (HAS_PCH_SPLIT(dev)) { int found; + dpd_is_edp = intel_dpd_is_edp(dev); + + if (has_edp_a(dev)) + intel_dp_init(dev, DP_A, PORT_A); if (I915_READ(HDMIB) & PORT_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ @@ -7603,11 +8491,15 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_C) & DP_DETECTED) intel_dp_init(dev, PCH_DP_C, PORT_C); - if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) + if (I915_READ(PCH_DP_D) & DP_DETECTED) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { int found; + /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ + if (I915_READ(DP_C) & DP_DETECTED) + intel_dp_init(dev, DP_C, PORT_C); + if (I915_READ(SDVOB) & PORT_DETECTED) { /* SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, SDVOB, true); @@ -7620,9 +8512,6 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(SDVOC) & PORT_DETECTED) intel_hdmi_init(dev, SDVOC, PORT_C); - /* Shares lanes with HDMI on SDVOC */ - if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; @@ -7676,8 +8565,9 @@ static void intel_setup_outputs(struct drm_device *dev) intel_encoder_clones(encoder); } - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) - ironlake_init_pch_refclk(dev); + intel_init_pch_refclk(dev); + + drm_helper_move_panel_connectors_to_head(dev); } static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) @@ -7718,27 +8608,51 @@ int intel_framebuffer_init(struct drm_device *dev, if (mode_cmd->pitches[0] & 63) return -EINVAL; + /* FIXME <= Gen4 stride limits are bit unclear */ + if (mode_cmd->pitches[0] > 32768) + return -EINVAL; + + if (obj->tiling_mode != I915_TILING_NONE && + mode_cmd->pitches[0] != obj->stride) + return -EINVAL; + + /* Reject formats not supported by any plane early. */ switch (mode_cmd->pixel_format) { - case DRM_FORMAT_RGB332: + case DRM_FORMAT_C8: case DRM_FORMAT_RGB565: case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ARGB8888: + break; + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: + if (INTEL_INFO(dev)->gen > 3) + return -EINVAL; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_ARGB2101010: - /* RGB formats are common across chipsets */ + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + if (INTEL_INFO(dev)->gen < 4) + return -EINVAL; break; case DRM_FORMAT_YUYV: case DRM_FORMAT_UYVY: case DRM_FORMAT_YVYU: case DRM_FORMAT_VYUY: + if (INTEL_INFO(dev)->gen < 6) + return -EINVAL; break; default: - DRM_DEBUG_KMS("unsupported pixel format %u\n", - mode_cmd->pixel_format); + DRM_DEBUG_KMS("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); return -EINVAL; } + /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ + if (mode_cmd->offsets[0] != 0) + return -EINVAL; + ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); @@ -7776,7 +8690,13 @@ 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_PCH_SPLIT(dev)) { + if (IS_HASWELL(dev)) { + 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.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; @@ -7827,6 +8747,8 @@ static void intel_init_display(struct drm_device *dev) /* FIXME: detect B0+ stepping and use auto training */ dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; dev_priv->display.write_eld = ironlake_write_eld; + dev_priv->display.modeset_global_resources = + ivb_modeset_global_resources; } else if (IS_HASWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; dev_priv->display.write_eld = haswell_write_eld; @@ -8058,6 +8980,7 @@ void intel_modeset_init(struct drm_device *dev) DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret); } + intel_cpu_pll_init(dev); intel_pch_pll_init(dev); /* Just disable it once at startup */ @@ -8127,7 +9050,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->pipe); + reg = PIPECONF(crtc->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 @@ -8246,7 +9169,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) /* Scan out the current hw modeset state, sanitizes it and maps it into the drm * and i915 state tracking structures. */ -void intel_modeset_setup_hw_state(struct drm_device *dev) +void intel_modeset_setup_hw_state(struct drm_device *dev, + bool force_restore) { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; @@ -8255,10 +9179,35 @@ void intel_modeset_setup_hw_state(struct drm_device *dev) struct intel_encoder *encoder; struct intel_connector *connector; + if (IS_HASWELL(dev)) { + tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); + + if (tmp & TRANS_DDI_FUNC_ENABLE) { + switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { + case TRANS_DDI_EDP_INPUT_A_ON: + case TRANS_DDI_EDP_INPUT_A_ONOFF: + pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + pipe = PIPE_C; + break; + } + + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + crtc->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]); - tmp = I915_READ(PIPECONF(pipe)); + tmp = I915_READ(PIPECONF(crtc->cpu_transcoder)); if (tmp & PIPECONF_ENABLE) crtc->active = true; else @@ -8271,6 +9220,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev) crtc->active ? "enabled" : "disabled"); } + if (IS_HASWELL(dev)) + intel_ddi_setup_hw_pll_state(dev); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { pipe = 0; @@ -8317,9 +9269,19 @@ void intel_modeset_setup_hw_state(struct drm_device *dev) intel_sanitize_crtc(crtc); } - intel_modeset_update_staged_output_state(dev); + if (force_restore) { + for_each_pipe(pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + intel_set_mode(&crtc->base, &crtc->base.mode, + crtc->base.x, crtc->base.y, crtc->base.fb); + } + } else { + intel_modeset_update_staged_output_state(dev); + } intel_modeset_check_state(dev); + + drm_mode_config_reset(dev); } void intel_modeset_gem_init(struct drm_device *dev) @@ -8328,7 +9290,7 @@ void intel_modeset_gem_init(struct drm_device *dev) intel_setup_overlay(dev); - intel_modeset_setup_hw_state(dev); + intel_modeset_setup_hw_state(dev, false); } void intel_modeset_cleanup(struct drm_device *dev) @@ -8447,6 +9409,7 @@ intel_display_capture_error_state(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_display_error_state *error; + enum transcoder cpu_transcoder; int i; error = kmalloc(sizeof(*error), GFP_ATOMIC); @@ -8454,6 +9417,8 @@ intel_display_capture_error_state(struct drm_device *dev) return NULL; 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)); @@ -8468,14 +9433,14 @@ intel_display_capture_error_state(struct drm_device *dev) error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i)); } - error->pipe[i].conf = I915_READ(PIPECONF(i)); + error->pipe[i].conf = I915_READ(PIPECONF(cpu_transcoder)); error->pipe[i].source = I915_READ(PIPESRC(i)); - error->pipe[i].htotal = I915_READ(HTOTAL(i)); - error->pipe[i].hblank = I915_READ(HBLANK(i)); - error->pipe[i].hsync = I915_READ(HSYNC(i)); - error->pipe[i].vtotal = I915_READ(VTOTAL(i)); - error->pipe[i].vblank = I915_READ(VBLANK(i)); - error->pipe[i].vsync = I915_READ(VSYNC(i)); + error->pipe[i].htotal = I915_READ(HTOTAL(cpu_transcoder)); + error->pipe[i].hblank = I915_READ(HBLANK(cpu_transcoder)); + error->pipe[i].hsync = I915_READ(HSYNC(cpu_transcoder)); + error->pipe[i].vtotal = I915_READ(VTOTAL(cpu_transcoder)); + error->pipe[i].vblank = I915_READ(VBLANK(cpu_transcoder)); + error->pipe[i].vsync = I915_READ(VSYNC(cpu_transcoder)); } return error; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 368ed8e..1b63d55 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -36,8 +36,6 @@ #include <drm/i915_drm.h> #include "i915_drv.h" -#define DP_RECEIVER_CAP_SIZE 0xf -#define DP_LINK_STATUS_SIZE 6 #define DP_LINK_CHECK_TIMEOUT (10 * 1000) /** @@ -49,7 +47,9 @@ */ static bool is_edp(struct intel_dp *intel_dp) { - return intel_dp->base.type == INTEL_OUTPUT_EDP; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + + return intel_dig_port->base.type == INTEL_OUTPUT_EDP; } /** @@ -76,15 +76,16 @@ static bool is_cpu_edp(struct intel_dp *intel_dp) return is_edp(intel_dp) && !is_pch_edp(intel_dp); } -static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) +static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) { - return container_of(encoder, struct intel_dp, base.base); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + + return intel_dig_port->base.base.dev; } static struct intel_dp *intel_attached_dp(struct drm_connector *connector) { - return container_of(intel_attached_encoder(connector), - struct intel_dp, base); + return enc_to_intel_dp(&intel_attached_encoder(connector)->base); } /** @@ -106,49 +107,32 @@ bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) return is_pch_edp(intel_dp); } -static void intel_dp_start_link_train(struct intel_dp *intel_dp); -static void intel_dp_complete_link_train(struct intel_dp *intel_dp); 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 = container_of(intel_encoder, struct intel_dp, base); + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); *lane_num = intel_dp->lane_count; - if (intel_dp->link_bw == DP_LINK_BW_1_62) - *link_bw = 162000; - else if (intel_dp->link_bw == DP_LINK_BW_2_7) - *link_bw = 270000; + *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 = container_of(intel_encoder, struct intel_dp, base); + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); + struct intel_connector *intel_connector = intel_dp->attached_connector; - if (intel_dp->panel_fixed_mode) - return intel_dp->panel_fixed_mode->clock; + if (intel_connector->panel.fixed_mode) + return intel_connector->panel.fixed_mode->clock; else return mode->clock; } static int -intel_dp_max_lane_count(struct intel_dp *intel_dp) -{ - int max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f; - switch (max_lane_count) { - case 1: case 2: case 4: - break; - default: - max_lane_count = 4; - } - return max_lane_count; -} - -static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; @@ -208,7 +192,7 @@ intel_dp_adjust_dithering(struct intel_dp *intel_dp, bool adjust_mode) { int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); - int max_lanes = intel_dp_max_lane_count(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); @@ -234,12 +218,14 @@ intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { 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; - if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { - if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) + if (is_edp(intel_dp) && fixed_mode) { + if (mode->hdisplay > fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay) + if (mode->vdisplay > fixed_mode->vdisplay) return MODE_PANEL; } @@ -285,6 +271,10 @@ intel_hrawclk(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t clkcfg; + /* There is no CLKCFG reg in Valleyview. VLV hrawclk is 200 MHz */ + if (IS_VALLEYVIEW(dev)) + return 200; + clkcfg = I915_READ(CLKCFG); switch (clkcfg & CLKCFG_FSB_MASK) { case CLKCFG_FSB_400: @@ -310,7 +300,7 @@ intel_hrawclk(struct drm_device *dev) static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0; @@ -318,7 +308,7 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0; @@ -327,7 +317,7 @@ static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) static void intel_dp_check_edp(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; if (!is_edp(intel_dp)) @@ -346,7 +336,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *recv, int recv_size) { uint32_t output_reg = intel_dp->output_reg; - struct drm_device *dev = intel_dp->base.base.dev; + 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_data = ch_ctl + 4; @@ -356,6 +347,29 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint32_t aux_clock_divider; int try, precharge; + 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 @@ -365,12 +379,16 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * clock divider. */ if (is_cpu_edp(intel_dp)) { - if (IS_GEN6(dev) || IS_GEN7(dev)) + if (IS_HASWELL(dev)) + aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1; + else if (IS_VALLEYVIEW(dev)) + aux_clock_divider = 100; + else if (IS_GEN6(dev) || IS_GEN7(dev)) 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)) - aux_clock_divider = 63; /* IRL input clock fixed at 125Mhz */ + aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2); else aux_clock_divider = intel_hrawclk(dev) / 2; @@ -642,9 +660,6 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, return -EREMOTEIO; } -static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); -static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); - static int intel_dp_i2c_init(struct intel_dp *intel_dp, struct intel_connector *intel_connector, const char *name) @@ -670,22 +685,25 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, return ret; } -static bool +bool intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_connector *intel_connector = intel_dp->attached_connector; int lane_count, clock; - int max_lane_count = intel_dp_max_lane_count(intel_dp); + 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 }; - if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { - intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode); - intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, + if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { + intel_fixed_panel_mode(intel_connector->panel.fixed_mode, + adjusted_mode); + intel_pch_panel_fitting(dev, + intel_connector->panel.fitting_mode, mode, adjusted_mode); } @@ -762,21 +780,23 @@ 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 *encoder; + 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_dp_m_n m_n; int pipe = intel_crtc->pipe; + enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; /* * Find the lane count in the intel_encoder private */ - for_each_encoder_on_crtc(dev, crtc, encoder) { - struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + intel_dp = enc_to_intel_dp(&intel_encoder->base); - if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT || - intel_dp->base.type == INTEL_OUTPUT_EDP) + if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || + intel_encoder->type == INTEL_OUTPUT_EDP) { lane_count = intel_dp->lane_count; break; @@ -791,23 +811,46 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, intel_dp_compute_m_n(intel_crtc->bpp, lane_count, mode->clock, adjusted_mode->clock, &m_n); - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(TRANSDATA_M1(pipe), - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); + 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), - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); + 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); } } +void intel_dp_init_link_config(struct intel_dp *intel_dp) +{ + memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); + intel_dp->link_configuration[0] = intel_dp->link_bw; + intel_dp->link_configuration[1] = intel_dp->lane_count; + intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B; + /* + * Check for DPCD version > 1.1 and enhanced framing support + */ + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && + (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) { + intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + } +} + static void intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -815,7 +858,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct drm_crtc *crtc = intel_dp->base.base.crtc; + struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); /* @@ -860,21 +903,12 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; intel_write_eld(encoder, adjusted_mode); } - memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); - intel_dp->link_configuration[0] = intel_dp->link_bw; - intel_dp->link_configuration[1] = intel_dp->lane_count; - intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B; - /* - * Check for DPCD version > 1.1 and enhanced framing support - */ - if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && - (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) { - intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - } + + intel_dp_init_link_config(intel_dp); /* Split out the IBX/CPU vs CPT settings */ - if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { + if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -931,7 +965,7 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, u32 mask, u32 value) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n", @@ -978,9 +1012,9 @@ static u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv) return control; } -static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) +void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; @@ -1019,7 +1053,7 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; @@ -1041,14 +1075,14 @@ static void ironlake_panel_vdd_work(struct work_struct *__work) { struct intel_dp *intel_dp = container_of(to_delayed_work(__work), struct intel_dp, panel_vdd_work); - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); mutex_lock(&dev->mode_config.mutex); ironlake_panel_vdd_off_sync(intel_dp); mutex_unlock(&dev->mode_config.mutex); } -static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) +void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) { if (!is_edp(intel_dp)) return; @@ -1071,9 +1105,9 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) } } -static void ironlake_edp_panel_on(struct intel_dp *intel_dp) +void ironlake_edp_panel_on(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; @@ -1113,9 +1147,9 @@ static void ironlake_edp_panel_on(struct intel_dp *intel_dp) } } -static void ironlake_edp_panel_off(struct intel_dp *intel_dp) +void ironlake_edp_panel_off(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; @@ -1138,10 +1172,12 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) ironlake_wait_panel_off(intel_dp); } -static void ironlake_edp_backlight_on(struct intel_dp *intel_dp) +void ironlake_edp_backlight_on(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + 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; + int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe; u32 pp; if (!is_edp(intel_dp)) @@ -1159,17 +1195,21 @@ static void ironlake_edp_backlight_on(struct intel_dp *intel_dp) pp |= EDP_BLC_ENABLE; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + + intel_panel_enable_backlight(dev, pipe); } -static void ironlake_edp_backlight_off(struct intel_dp *intel_dp) +void ironlake_edp_backlight_off(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; if (!is_edp(intel_dp)) return; + intel_panel_disable_backlight(dev); + DRM_DEBUG_KMS("\n"); pp = ironlake_get_pp_control(dev_priv); pp &= ~EDP_BLC_ENABLE; @@ -1180,8 +1220,9 @@ static void ironlake_edp_backlight_off(struct intel_dp *intel_dp) static void ironlake_edp_pll_on(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; - struct drm_crtc *crtc = intel_dp->base.base.crtc; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_crtc *crtc = intel_dig_port->base.base.crtc; + struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 dpa_ctl; @@ -1205,8 +1246,9 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp) static void ironlake_edp_pll_off(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; - struct drm_crtc *crtc = intel_dp->base.base.crtc; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_crtc *crtc = intel_dig_port->base.base.crtc; + struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 dpa_ctl; @@ -1228,7 +1270,7 @@ static void ironlake_edp_pll_off(struct intel_dp *intel_dp) } /* If the sink supports it, try to set the power state appropriately */ -static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) +void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) { int ret, i; @@ -1298,9 +1340,10 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, return true; } } - } - DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", intel_dp->output_reg); + DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", + intel_dp->output_reg); + } return true; } @@ -1396,38 +1439,6 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ DP_LINK_STATUS_SIZE); } -static uint8_t -intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], - int r) -{ - return link_status[r - DP_LANE0_1_STATUS]; -} - -static uint8_t -intel_get_adjust_request_voltage(uint8_t adjust_request[2], - int lane) -{ - int s = ((lane & 1) ? - DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : - DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); - uint8_t l = adjust_request[lane>>1]; - - return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; -} - -static uint8_t -intel_get_adjust_request_pre_emphasis(uint8_t adjust_request[2], - int lane) -{ - int s = ((lane & 1) ? - DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : - DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); - uint8_t l = adjust_request[lane>>1]; - - return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; -} - - #if 0 static char *voltage_names[] = { "0.4V", "0.6V", "0.8V", "1.2V" @@ -1448,7 +1459,7 @@ static char *link_train_names[] = { static uint8_t intel_dp_voltage_max(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) return DP_TRAIN_VOLTAGE_SWING_800; @@ -1461,9 +1472,21 @@ intel_dp_voltage_max(struct intel_dp *intel_dp) static uint8_t intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + if (IS_HASWELL(dev)) { + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + return DP_TRAIN_PRE_EMPHASIS_9_5; + case DP_TRAIN_VOLTAGE_SWING_600: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_800: + return DP_TRAIN_PRE_EMPHASIS_3_5; + case DP_TRAIN_VOLTAGE_SWING_1200: + default: + return DP_TRAIN_PRE_EMPHASIS_0; + } + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: return DP_TRAIN_PRE_EMPHASIS_6; @@ -1494,13 +1517,12 @@ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ST uint8_t v = 0; uint8_t p = 0; int lane; - uint8_t *adjust_request = link_status + (DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS); uint8_t voltage_max; uint8_t preemph_max; for (lane = 0; lane < intel_dp->lane_count; lane++) { - uint8_t this_v = intel_get_adjust_request_voltage(adjust_request, lane); - uint8_t this_p = intel_get_adjust_request_pre_emphasis(adjust_request, lane); + uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane); + uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); if (this_v > v) v = this_v; @@ -1617,52 +1639,38 @@ intel_gen7_edp_signal_levels(uint8_t train_set) } } -static uint8_t -intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], - int lane) -{ - int s = (lane & 1) * 4; - uint8_t l = link_status[lane>>1]; - - return (l >> s) & 0xf; -} - -/* Check for clock recovery is done on all channels */ -static bool -intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) +/* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */ +static uint32_t +intel_dp_signal_levels_hsw(uint8_t train_set) { - int lane; - uint8_t lane_status; - - for (lane = 0; lane < lane_count; lane++) { - lane_status = intel_get_lane_status(link_status, lane); - if ((lane_status & DP_LANE_CR_DONE) == 0) - return false; - } - return true; -} + int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | + DP_TRAIN_PRE_EMPHASIS_MASK); + switch (signal_levels) { + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0: + return DDI_BUF_EMP_400MV_0DB_HSW; + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5: + return DDI_BUF_EMP_400MV_3_5DB_HSW; + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6: + return DDI_BUF_EMP_400MV_6DB_HSW; + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_9_5: + return DDI_BUF_EMP_400MV_9_5DB_HSW; -/* Check to see if channel eq is done on all channels */ -#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\ - DP_LANE_CHANNEL_EQ_DONE|\ - DP_LANE_SYMBOL_LOCKED) -static bool -intel_channel_eq_ok(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) -{ - uint8_t lane_align; - uint8_t lane_status; - int lane; + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0: + return DDI_BUF_EMP_600MV_0DB_HSW; + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5: + return DDI_BUF_EMP_600MV_3_5DB_HSW; + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6: + return DDI_BUF_EMP_600MV_6DB_HSW; - lane_align = intel_dp_link_status(link_status, - DP_LANE_ALIGN_STATUS_UPDATED); - if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) - return false; - for (lane = 0; lane < intel_dp->lane_count; lane++) { - lane_status = intel_get_lane_status(link_status, lane); - if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) - return false; + case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0: + return DDI_BUF_EMP_800MV_0DB_HSW; + case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5: + return DDI_BUF_EMP_800MV_3_5DB_HSW; + default: + DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:" + "0x%x\n", signal_levels); + return DDI_BUF_EMP_400MV_0DB_HSW; } - return true; } static bool @@ -1670,11 +1678,49 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, uint8_t dp_train_pat) { - struct drm_device *dev = intel_dp->base.base.dev; + 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; + enum port port = intel_dig_port->port; int ret; + uint32_t temp; - if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) { + if (IS_HASWELL(dev)) { + temp = I915_READ(DP_TP_CTL(port)); + + if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) + temp |= DP_TP_CTL_SCRAMBLE_DISABLE; + else + temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE; + + temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; + switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { + case DP_TRAINING_PATTERN_DISABLE: + temp |= DP_TP_CTL_LINK_TRAIN_IDLE; + I915_WRITE(DP_TP_CTL(port), temp); + + if (wait_for((I915_READ(DP_TP_STATUS(port)) & + DP_TP_STATUS_IDLE_DONE), 1)) + DRM_ERROR("Timed out waiting for DP idle patterns\n"); + + temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; + temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; + + break; + case DP_TRAINING_PATTERN_1: + temp |= DP_TP_CTL_LINK_TRAIN_PAT1; + break; + case DP_TRAINING_PATTERN_2: + temp |= DP_TP_CTL_LINK_TRAIN_PAT2; + break; + case DP_TRAINING_PATTERN_3: + temp |= DP_TP_CTL_LINK_TRAIN_PAT3; + break; + } + I915_WRITE(DP_TP_CTL(port), temp); + + } else if (HAS_PCH_CPT(dev) && + (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) { dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { @@ -1734,16 +1780,20 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, } /* Enable corresponding port and start training pattern 1 */ -static void +void intel_dp_start_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base; + struct drm_device *dev = encoder->dev; int i; uint8_t voltage; bool clock_recovery = false; int voltage_tries, loop_tries; uint32_t DP = intel_dp->DP; + if (IS_HASWELL(dev)) + intel_ddi_prepare_link_retrain(encoder); + /* Write the link configuration data */ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, intel_dp->link_configuration, @@ -1761,8 +1811,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) uint8_t link_status[DP_LINK_STATUS_SIZE]; uint32_t signal_levels; - - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + if (IS_HASWELL(dev)) { + signal_levels = intel_dp_signal_levels_hsw( + intel_dp->train_set[0]); + DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels; + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { @@ -1770,23 +1823,24 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); - DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n", signal_levels); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } + DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n", + signal_levels); + /* Set training pattern 1 */ if (!intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE)) break; - /* Set training pattern 1 */ - udelay(100); + drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); if (!intel_dp_get_link_status(intel_dp, link_status)) { DRM_ERROR("failed to get link status\n"); break; } - if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { + if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { DRM_DEBUG_KMS("clock recovery OK\n"); clock_recovery = true; break; @@ -1825,10 +1879,10 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) intel_dp->DP = DP; } -static void +void intel_dp_complete_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); bool channel_eq = false; int tries, cr_tries; uint32_t DP = intel_dp->DP; @@ -1848,7 +1902,10 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; } - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + if (IS_HASWELL(dev)) { + signal_levels = intel_dp_signal_levels_hsw(intel_dp->train_set[0]); + DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels; + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { @@ -1865,18 +1922,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) DP_LINK_SCRAMBLING_DISABLE)) break; - udelay(400); + drm_dp_link_train_channel_eq_delay(intel_dp->dpcd); if (!intel_dp_get_link_status(intel_dp, link_status)) break; /* Make sure clock is still ok */ - if (!intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { + if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { intel_dp_start_link_train(intel_dp); cr_tries++; continue; } - if (intel_channel_eq_ok(intel_dp, link_status)) { + if (drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) { channel_eq = true; break; } @@ -1895,16 +1952,38 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ++tries; } + if (channel_eq) + DRM_DEBUG_KMS("Channel EQ done. DP Training successfull\n"); + intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE); } static void intel_dp_link_down(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + 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 DP = intel_dp->DP; + /* + * DDI code has a strict mode set sequence and we should try to respect + * it, otherwise we might hang the machine in many different ways. So we + * really should be disabling the port only on a complete crtc_disable + * sequence. This function is just called under two conditions on DDI + * code: + * - Link train failed while doing crtc_enable, and on this case we + * really should respect the mode set sequence and wait for a + * crtc_disable. + * - Someone turned the monitor off and intel_dp_check_link_status + * called us. We don't need to disable the whole port on this case, so + * when someone turns the monitor on again, + * intel_ddi_prepare_link_retrain will take care of redoing the link + * train. + */ + if (IS_HASWELL(dev)) + return; + if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)) return; @@ -1923,7 +2002,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (HAS_PCH_IBX(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { - struct drm_crtc *crtc = intel_dp->base.base.crtc; + struct drm_crtc *crtc = intel_dig_port->base.base.crtc; /* Hardware workaround: leaving our transcoder select * set to transcoder B while it's off will prevent the @@ -2024,7 +2103,7 @@ static void intel_dp_handle_test_request(struct intel_dp *intel_dp) { /* NAK by default */ - intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_ACK); + intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_NAK); } /* @@ -2036,16 +2115,17 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp) * 4. Check link status on receipt of hot-plug interrupt */ -static void +void intel_dp_check_link_status(struct intel_dp *intel_dp) { + struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base; u8 sink_irq_vector; u8 link_status[DP_LINK_STATUS_SIZE]; - if (!intel_dp->base.connectors_active) + if (!intel_encoder->connectors_active) return; - if (WARN_ON(!intel_dp->base.base.crtc)) + if (WARN_ON(!intel_encoder->base.crtc)) return; /* Try to read receiver status if the link appears to be up */ @@ -2074,9 +2154,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); } - if (!intel_channel_eq_ok(intel_dp, link_status)) { + if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) { DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", - drm_get_encoder_name(&intel_dp->base.base)); + drm_get_encoder_name(&intel_encoder->base)); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); } @@ -2125,11 +2205,12 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp) static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { + struct drm_device *dev = intel_dp_to_dev(intel_dp); enum drm_connector_status status; /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) { - status = intel_panel_detect(intel_dp->base.base.dev); + status = intel_panel_detect(dev); if (status == connector_status_unknown) status = connector_status_connected; return status; @@ -2141,7 +2222,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp) static enum drm_connector_status g4x_dp_detect(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; uint32_t bit; @@ -2168,44 +2249,45 @@ g4x_dp_detect(struct intel_dp *intel_dp) static struct edid * intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { - struct intel_dp *intel_dp = intel_attached_dp(connector); - struct edid *edid; - int size; + struct intel_connector *intel_connector = to_intel_connector(connector); - if (is_edp(intel_dp)) { - if (!intel_dp->edid) + /* use cached edid if we have one */ + if (intel_connector->edid) { + struct edid *edid; + int size; + + /* invalid edid */ + if (IS_ERR(intel_connector->edid)) return NULL; - size = (intel_dp->edid->extensions + 1) * EDID_LENGTH; + size = (intel_connector->edid->extensions + 1) * EDID_LENGTH; edid = kmalloc(size, GFP_KERNEL); if (!edid) return NULL; - memcpy(edid, intel_dp->edid, size); + memcpy(edid, intel_connector->edid, size); return edid; } - edid = drm_get_edid(connector, adapter); - return edid; + return drm_get_edid(connector, adapter); } static int intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter) { - struct intel_dp *intel_dp = intel_attached_dp(connector); - int ret; + struct intel_connector *intel_connector = to_intel_connector(connector); - if (is_edp(intel_dp)) { - drm_mode_connector_update_edid_property(connector, - intel_dp->edid); - ret = drm_add_edid_modes(connector, intel_dp->edid); - drm_edid_to_eld(connector, - intel_dp->edid); - return intel_dp->edid_mode_count; + /* use cached edid if we have one */ + if (intel_connector->edid) { + /* invalid edid */ + if (IS_ERR(intel_connector->edid)) + return 0; + + return intel_connector_update_modes(connector, + intel_connector->edid); } - ret = intel_ddc_get_modes(connector, adapter); - return ret; + return intel_ddc_get_modes(connector, adapter); } @@ -2219,9 +2301,12 @@ static enum drm_connector_status intel_dp_detect(struct drm_connector *connector, bool force) { struct intel_dp *intel_dp = intel_attached_dp(connector); - struct drm_device *dev = intel_dp->base.base.dev; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; + struct drm_device *dev = connector->dev; enum drm_connector_status status; struct edid *edid = NULL; + char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3]; intel_dp->has_audio = false; @@ -2230,10 +2315,9 @@ intel_dp_detect(struct drm_connector *connector, bool force) else status = g4x_dp_detect(intel_dp); - DRM_DEBUG_KMS("DPCD: %02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n", - intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], - intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5], - intel_dp->dpcd[6], intel_dp->dpcd[7]); + hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd), + 32, 1, dpcd_hex_dump, sizeof(dpcd_hex_dump), false); + DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); if (status != connector_status_connected) return status; @@ -2250,49 +2334,31 @@ intel_dp_detect(struct drm_connector *connector, bool force) } } + if (intel_encoder->type != INTEL_OUTPUT_EDP) + intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; return connector_status_connected; } static int intel_dp_get_modes(struct drm_connector *connector) { struct intel_dp *intel_dp = intel_attached_dp(connector); - struct drm_device *dev = intel_dp->base.base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct drm_device *dev = connector->dev; int ret; /* We should parse the EDID data and find out if it has an audio sink */ ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter); - if (ret) { - if (is_edp(intel_dp) && !intel_dp->panel_fixed_mode) { - struct drm_display_mode *newmode; - list_for_each_entry(newmode, &connector->probed_modes, - head) { - if ((newmode->type & DRM_MODE_TYPE_PREFERRED)) { - intel_dp->panel_fixed_mode = - drm_mode_duplicate(dev, newmode); - break; - } - } - } + if (ret) return ret; - } - /* if eDP has no EDID, try to use fixed panel mode from VBT */ - if (is_edp(intel_dp)) { - /* initialize panel mode from VBT if available for eDP */ - if (intel_dp->panel_fixed_mode == NULL && dev_priv->lfp_lvds_vbt_mode != NULL) { - intel_dp->panel_fixed_mode = - drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (intel_dp->panel_fixed_mode) { - intel_dp->panel_fixed_mode->type |= - DRM_MODE_TYPE_PREFERRED; - } - } - if (intel_dp->panel_fixed_mode) { - struct drm_display_mode *mode; - mode = drm_mode_duplicate(dev, intel_dp->panel_fixed_mode); + /* if eDP has no EDID, fall back to fixed mode */ + if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { + struct drm_display_mode *mode; + mode = drm_mode_duplicate(dev, + intel_connector->panel.fixed_mode); + if (mode) { drm_mode_probed_add(connector, mode); return 1; } @@ -2322,10 +2388,12 @@ intel_dp_set_property(struct drm_connector *connector, uint64_t val) { struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_encoder *intel_encoder = intel_attached_encoder(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); int ret; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; @@ -2358,11 +2426,27 @@ intel_dp_set_property(struct drm_connector *connector, goto done; } + if (is_edp(intel_dp) && + property == connector->dev->mode_config.scaling_mode_property) { + if (val == DRM_MODE_SCALE_NONE) { + DRM_DEBUG_KMS("no scaling not supported\n"); + return -EINVAL; + } + + if (intel_connector->panel.fitting_mode == val) { + /* the eDP scaling property is not changed */ + return 0; + } + intel_connector->panel.fitting_mode = val; + + goto done; + } + return -EINVAL; done: - if (intel_dp->base.base.crtc) { - struct drm_crtc *crtc = intel_dp->base.base.crtc; + if (intel_encoder->base.crtc) { + struct drm_crtc *crtc = intel_encoder->base.crtc; intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); } @@ -2375,27 +2459,33 @@ 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_edp(intel_dp)) + if (!IS_ERR_OR_NULL(intel_connector->edid)) + kfree(intel_connector->edid); + + if (is_edp(intel_dp)) { intel_panel_destroy_backlight(dev); + intel_panel_fini(&intel_connector->panel); + } drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(connector); } -static void intel_dp_encoder_destroy(struct drm_encoder *encoder) +void intel_dp_encoder_destroy(struct drm_encoder *encoder) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_dp *intel_dp = &intel_dig_port->dp; i2c_del_adapter(&intel_dp->adapter); drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { - kfree(intel_dp->edid); cancel_delayed_work_sync(&intel_dp->panel_vdd_work); ironlake_panel_vdd_off_sync(intel_dp); } - kfree(intel_dp); + kfree(intel_dig_port); } static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { @@ -2425,7 +2515,7 @@ static const struct drm_encoder_funcs intel_dp_enc_funcs = { static void intel_dp_hot_plug(struct intel_encoder *intel_encoder) { - struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); intel_dp_check_link_status(intel_dp); } @@ -2435,13 +2525,14 @@ int intel_trans_dp_port_sel(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct intel_encoder *encoder; + struct intel_encoder *intel_encoder; + struct intel_dp *intel_dp; - for_each_encoder_on_crtc(dev, crtc, encoder) { - struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + intel_dp = enc_to_intel_dp(&intel_encoder->base); - if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT || - intel_dp->base.type == INTEL_OUTPUT_EDP) + if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || + intel_encoder->type == INTEL_OUTPUT_EDP) return intel_dp->output_reg; } @@ -2471,78 +2562,191 @@ bool intel_dpd_is_edp(struct drm_device *dev) static void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector) { + struct intel_connector *intel_connector = to_intel_connector(connector); + intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + + if (is_edp(intel_dp)) { + drm_mode_create_scaling_mode_property(connector->dev); + drm_object_attach_property( + &connector->base, + connector->dev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_ASPECT); + intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT; + } +} + +static void +intel_dp_init_panel_power_sequencer(struct drm_device *dev, + struct intel_dp *intel_dp) +{ + 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; + + /* 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_on = I915_READ(PCH_PP_ON_DELAYS); + pp_off = I915_READ(PCH_PP_OFF_DELAYS); + pp_div = I915_READ(PCH_PP_DIVISOR); + + /* Pull timing values out of registers */ + cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> + PANEL_POWER_UP_DELAY_SHIFT; + + cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >> + PANEL_LIGHT_ON_DELAY_SHIFT; + + cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >> + PANEL_LIGHT_OFF_DELAY_SHIFT; + + cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> + PANEL_POWER_DOWN_DELAY_SHIFT; + + cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> + PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000; + + DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", + cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); + + vbt = dev_priv->edp.pps; + + /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of + * our hw here, which are all in 100usec. */ + spec.t1_t3 = 210 * 10; + spec.t8 = 50 * 10; /* no limit for t8, use t7 instead */ + spec.t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */ + spec.t10 = 500 * 10; + /* This one is special and actually in units of 100ms, but zero + * based in the hw (so we need to add 100 ms). But the sw vbt + * table multiplies it with 1000 to make it in units of 100usec, + * too. */ + spec.t11_t12 = (510 + 100) * 10; + + DRM_DEBUG_KMS("vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", + vbt.t1_t3, vbt.t8, vbt.t9, vbt.t10, vbt.t11_t12); + + /* Use the max of the register settings and vbt. If both are + * unset, fall back to the spec limits. */ +#define assign_final(field) final.field = (max(cur.field, vbt.field) == 0 ? \ + spec.field : \ + max(cur.field, vbt.field)) + assign_final(t1_t3); + assign_final(t8); + assign_final(t9); + assign_final(t10); + assign_final(t11_t12); +#undef assign_final + +#define get_delay(field) (DIV_ROUND_UP(final.field, 10)) + intel_dp->panel_power_up_delay = get_delay(t1_t3); + intel_dp->backlight_on_delay = get_delay(t8); + intel_dp->backlight_off_delay = get_delay(t9); + intel_dp->panel_power_down_delay = get_delay(t10); + intel_dp->panel_power_cycle_delay = get_delay(t11_t12); +#undef get_delay + + /* And finally store the new values in the power sequencer. */ + pp_on = (final.t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | + (final.t8 << PANEL_LIGHT_ON_DELAY_SHIFT); + pp_off = (final.t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) | + (final.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 |= (DIV_ROUND_UP(final.t11_t12, 1000) + << PANEL_POWER_CYCLE_DELAY_SHIFT); + + /* Haswell doesn't have any port selection bits for the panel + * 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; + else + pp_on |= 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); + + + DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n", + intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay, + intel_dp->panel_power_cycle_delay); + + DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", + intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); + + 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)); } void -intel_dp_init(struct drm_device *dev, int output_reg, enum port port) +intel_dp_init_connector(struct intel_digital_port *intel_dig_port, + struct intel_connector *intel_connector) { + struct drm_connector *connector = &intel_connector->base; + struct intel_dp *intel_dp = &intel_dig_port->dp; + struct intel_encoder *intel_encoder = &intel_dig_port->base; + struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_connector *connector; - struct intel_dp *intel_dp; - struct intel_encoder *intel_encoder; - struct intel_connector *intel_connector; + struct drm_display_mode *fixed_mode = NULL; + enum port port = intel_dig_port->port; const char *name = NULL; int type; - intel_dp = kzalloc(sizeof(struct intel_dp), GFP_KERNEL); - if (!intel_dp) - return; - - intel_dp->output_reg = output_reg; - intel_dp->port = port; /* Preserve the current hw state. */ intel_dp->DP = I915_READ(intel_dp->output_reg); + intel_dp->attached_connector = intel_connector; - intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); - if (!intel_connector) { - kfree(intel_dp); - return; - } - intel_encoder = &intel_dp->base; - - if (HAS_PCH_SPLIT(dev) && output_reg == PCH_DP_D) + if (HAS_PCH_SPLIT(dev) && port == PORT_D) if (intel_dpd_is_edp(dev)) intel_dp->is_pch_edp = true; - if (output_reg == DP_A || is_pch_edp(intel_dp)) { + /* + * FIXME : We need to initialize built-in panels before external panels. + * For X0, DP_C is fixed as eDP. Revisit this as part of VLV eDP cleanup + */ + if (IS_VALLEYVIEW(dev) && port == PORT_C) { + type = DRM_MODE_CONNECTOR_eDP; + intel_encoder->type = INTEL_OUTPUT_EDP; + } else if (port == PORT_A || is_pch_edp(intel_dp)) { type = DRM_MODE_CONNECTOR_eDP; intel_encoder->type = INTEL_OUTPUT_EDP; } else { + /* The intel_encoder->type value may be INTEL_OUTPUT_UNKNOWN for + * DDI or INTEL_OUTPUT_DISPLAYPORT for the older gens, so don't + * rewrite it. + */ type = DRM_MODE_CONNECTOR_DisplayPort; - intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; } - connector = &intel_connector->base; 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; - - intel_encoder->cloneable = false; - - INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, - ironlake_panel_vdd_work); - - intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - connector->interlace_allowed = true; connector->doublescan_allowed = 0; - drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs, - DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); + INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, + ironlake_panel_vdd_work); intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); - intel_encoder->enable = intel_enable_dp; - intel_encoder->pre_enable = intel_pre_enable_dp; - intel_encoder->disable = intel_disable_dp; - intel_encoder->post_disable = intel_post_disable_dp; - intel_encoder->get_hw_state = intel_dp_get_hw_state; - intel_connector->get_hw_state = intel_connector_get_hw_state; + if (IS_HASWELL(dev)) + intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; + else + intel_connector->get_hw_state = intel_connector_get_hw_state; + /* Set up the DDC bus. */ switch (port) { @@ -2566,66 +2770,15 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) break; } - /* Cache some DPCD data in the eDP case */ - if (is_edp(intel_dp)) { - struct edp_power_seq cur, vbt; - u32 pp_on, pp_off, pp_div; - - pp_on = I915_READ(PCH_PP_ON_DELAYS); - pp_off = I915_READ(PCH_PP_OFF_DELAYS); - pp_div = I915_READ(PCH_PP_DIVISOR); - - if (!pp_on || !pp_off || !pp_div) { - DRM_INFO("bad panel power sequencing delays, disabling panel\n"); - intel_dp_encoder_destroy(&intel_dp->base.base); - intel_dp_destroy(&intel_connector->base); - return; - } - - /* Pull timing values out of registers */ - cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> - PANEL_POWER_UP_DELAY_SHIFT; - - cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >> - PANEL_LIGHT_ON_DELAY_SHIFT; - - cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >> - PANEL_LIGHT_OFF_DELAY_SHIFT; - - cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> - PANEL_POWER_DOWN_DELAY_SHIFT; - - cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> - PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000; - - DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", - cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); - - vbt = dev_priv->edp.pps; - - DRM_DEBUG_KMS("vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", - vbt.t1_t3, vbt.t8, vbt.t9, vbt.t10, vbt.t11_t12); - -#define get_delay(field) ((max(cur.field, vbt.field) + 9) / 10) - - intel_dp->panel_power_up_delay = get_delay(t1_t3); - intel_dp->backlight_on_delay = get_delay(t8); - intel_dp->backlight_off_delay = get_delay(t9); - intel_dp->panel_power_down_delay = get_delay(t10); - intel_dp->panel_power_cycle_delay = get_delay(t11_t12); - - DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n", - intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay, - intel_dp->panel_power_cycle_delay); - - DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", - intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); - } + if (is_edp(intel_dp)) + intel_dp_init_panel_power_sequencer(dev, intel_dp); intel_dp_i2c_init(intel_dp, intel_connector, name); + /* Cache DPCD and EDID for edp. */ if (is_edp(intel_dp)) { bool ret; + struct drm_display_mode *scan; struct edid *edid; ironlake_edp_panel_vdd_on(intel_dp); @@ -2640,29 +2793,47 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) } else { /* if this fails, presume the device is a ghost */ DRM_INFO("failed to retrieve link info, disabling eDP\n"); - intel_dp_encoder_destroy(&intel_dp->base.base); - intel_dp_destroy(&intel_connector->base); + intel_dp_encoder_destroy(&intel_encoder->base); + intel_dp_destroy(connector); return; } ironlake_edp_panel_vdd_on(intel_dp); edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, - edid); - intel_dp->edid_mode_count = - drm_add_edid_modes(connector, edid); - drm_edid_to_eld(connector, edid); - intel_dp->edid = edid; + if (drm_add_edid_modes(connector, edid)) { + drm_mode_connector_update_edid_property(connector, edid); + drm_edid_to_eld(connector, edid); + } else { + kfree(edid); + edid = ERR_PTR(-EINVAL); + } + } else { + edid = ERR_PTR(-ENOENT); + } + intel_connector->edid = edid; + + /* prefer fixed mode from EDID if available */ + list_for_each_entry(scan, &connector->probed_modes, head) { + if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { + fixed_mode = drm_mode_duplicate(dev, scan); + break; + } } + + /* fallback to VBT if available for eDP */ + if (!fixed_mode && dev_priv->lfp_lvds_vbt_mode) { + fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (fixed_mode) + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + } + ironlake_edp_panel_vdd_off(intel_dp, false); } - intel_encoder->hot_plug = intel_dp_hot_plug; - if (is_edp(intel_dp)) { - dev_priv->int_edp_connector = connector; - intel_panel_setup_backlight(dev); + intel_panel_init(&intel_connector->panel, fixed_mode); + intel_panel_setup_backlight(connector); } intel_dp_add_properties(intel_dp, connector); @@ -2676,3 +2847,45 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } } + +void +intel_dp_init(struct drm_device *dev, int output_reg, enum port port) +{ + struct intel_digital_port *intel_dig_port; + struct intel_encoder *intel_encoder; + struct drm_encoder *encoder; + struct intel_connector *intel_connector; + + intel_dig_port = kzalloc(sizeof(struct intel_digital_port), GFP_KERNEL); + if (!intel_dig_port) + return; + + intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); + if (!intel_connector) { + kfree(intel_dig_port); + return; + } + + intel_encoder = &intel_dig_port->base; + encoder = &intel_encoder->base; + + drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); + + intel_encoder->enable = intel_enable_dp; + intel_encoder->pre_enable = intel_pre_enable_dp; + intel_encoder->disable = intel_disable_dp; + intel_encoder->post_disable = intel_post_disable_dp; + intel_encoder->get_hw_state = intel_dp_get_hw_state; + + intel_dig_port->port = port; + intel_dig_port->dp.output_reg = output_reg; + + intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; + intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + intel_encoder->cloneable = false; + intel_encoder->hot_plug = intel_dp_hot_plug; + + intel_dp_init_connector(intel_dig_port, intel_connector); +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fe71425..8a1bd4a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -94,6 +94,7 @@ #define INTEL_OUTPUT_HDMI 6 #define INTEL_OUTPUT_DISPLAYPORT 7 #define INTEL_OUTPUT_EDP 8 +#define INTEL_OUTPUT_UNKNOWN 9 #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 @@ -163,6 +164,11 @@ struct intel_encoder { int crtc_mask; }; +struct intel_panel { + struct drm_display_mode *fixed_mode; + int fitting_mode; +}; + struct intel_connector { struct drm_connector base; /* @@ -179,12 +185,19 @@ struct intel_connector { /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); + + /* Panel info for eDP and LVDS */ + struct intel_panel panel; + + /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ + struct edid *edid; }; 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 @@ -198,6 +211,8 @@ struct intel_crtc { struct intel_unpin_work *unpin_work; int fdi_lanes; + atomic_t unpin_work_count; + /* Display surface base address adjustement for pageflips. Note that on * gen4+ this only adjusts up to a tile, offsets within a tile are * handled in the hw itself (with the TILEOFF register). */ @@ -212,12 +227,14 @@ struct intel_crtc { /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; + uint32_t ddi_pll_sel; }; struct intel_plane { struct drm_plane base; 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]; void (*update_plane)(struct drm_plane *plane, @@ -317,10 +334,8 @@ struct dip_infoframe { } __attribute__((packed)); struct intel_hdmi { - struct intel_encoder base; u32 sdvox_reg; int ddc_bus; - int ddi_port; uint32_t color_range; bool has_hdmi_sink; bool has_audio; @@ -331,18 +346,15 @@ struct intel_hdmi { struct drm_display_mode *adjusted_mode); }; -#define DP_RECEIVER_CAP_SIZE 0xf #define DP_MAX_DOWNSTREAM_PORTS 0x10 #define DP_LINK_CONFIGURATION_SIZE 9 struct intel_dp { - struct intel_encoder base; uint32_t output_reg; uint32_t DP; uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; bool has_audio; enum hdmi_force_audio force_audio; - enum port port; uint32_t color_range; uint8_t link_bw; uint8_t lane_count; @@ -357,11 +369,16 @@ struct intel_dp { int panel_power_cycle_delay; int backlight_on_delay; int backlight_off_delay; - struct drm_display_mode *panel_fixed_mode; /* for eDP */ struct delayed_work panel_vdd_work; bool want_panel_vdd; - struct edid *edid; /* cached EDID for eDP */ - int edid_mode_count; + struct intel_connector *attached_connector; +}; + +struct intel_digital_port { + struct intel_encoder base; + enum port port; + struct intel_dp dp; + struct intel_hdmi hdmi; }; static inline struct drm_crtc * @@ -380,11 +397,14 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane) struct intel_unpin_work { struct work_struct work; - struct drm_device *dev; + struct drm_crtc *crtc; struct drm_i915_gem_object *old_fb_obj; struct drm_i915_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; - int pending; + atomic_t pending; +#define INTEL_FLIP_INACTIVE 0 +#define INTEL_FLIP_PENDING 1 +#define INTEL_FLIP_COMPLETE 2 bool enable_stall_check; }; @@ -395,6 +415,8 @@ struct intel_fbc_work { int interval; }; +int intel_pch_rawclk(struct drm_device *dev); + int intel_connector_update_modes(struct drm_connector *connector, struct edid *edid); int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); @@ -405,7 +427,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); +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 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); @@ -418,10 +445,27 @@ extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj); extern bool intel_lvds_init(struct drm_device *dev); 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_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); +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); @@ -431,6 +475,10 @@ extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane); /* intel_panel.c */ +extern int intel_panel_init(struct intel_panel *panel, + struct drm_display_mode *fixed_mode); +extern void intel_panel_fini(struct intel_panel *panel); + extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); extern void intel_pch_panel_fitting(struct drm_device *dev, @@ -439,7 +487,7 @@ extern void intel_pch_panel_fitting(struct drm_device *dev, struct drm_display_mode *adjusted_mode); extern u32 intel_panel_get_max_backlight(struct drm_device *dev); extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); -extern int intel_panel_setup_backlight(struct drm_device *dev); +extern int intel_panel_setup_backlight(struct drm_connector *connector); extern void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe); extern void intel_panel_disable_backlight(struct drm_device *dev); @@ -473,6 +521,31 @@ static inline struct intel_encoder *intel_attached_encoder(struct drm_connector return to_intel_connector(connector)->encoder; } +static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) +{ + struct intel_digital_port *intel_dig_port = + container_of(encoder, struct intel_digital_port, base.base); + return &intel_dig_port->dp; +} + +static inline struct intel_digital_port * +enc_to_dig_port(struct drm_encoder *encoder) +{ + return container_of(encoder, struct intel_digital_port, base.base); +} + +static inline struct intel_digital_port * +dp_to_dig_port(struct intel_dp *intel_dp) +{ + return container_of(intel_dp, struct intel_digital_port, dp); +} + +static inline struct intel_digital_port * +hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) +{ + return container_of(intel_hdmi, struct intel_digital_port, hdmi); +} + extern void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder); extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); @@ -481,8 +554,12 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern enum transcoder +intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe); extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); +extern int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); struct intel_load_detect_pipe { struct drm_framebuffer *release_fb; @@ -550,6 +627,10 @@ extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe, struct drm_display_mode *mode); +extern unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y, + unsigned int bpp, + unsigned int pitch); + extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, @@ -573,12 +654,22 @@ extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); extern void ironlake_teardown_rc6(struct drm_device *dev); -extern void intel_enable_ddi(struct intel_encoder *encoder); -extern void intel_disable_ddi(struct intel_encoder *encoder); extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe); -extern void intel_ddi_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); +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_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); +extern void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); +extern void intel_ddi_setup_hw_pll_state(struct drm_device *dev); +extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock); +extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); +extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); +extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); +extern bool +intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); +extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9ba0aae..2ee9821 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -36,10 +36,15 @@ #include <drm/i915_drm.h> #include "i915_drv.h" +static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) +{ + return hdmi_to_dig_port(intel_hdmi)->base.base.dev; +} + static void assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) { - struct drm_device *dev = intel_hdmi->base.base.dev; + struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); struct drm_i915_private *dev_priv = dev->dev_private; uint32_t enabled_bits; @@ -51,13 +56,14 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) { - return container_of(encoder, struct intel_hdmi, base.base); + struct intel_digital_port *intel_dig_port = + container_of(encoder, struct intel_digital_port, base.base); + return &intel_dig_port->hdmi; } static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) { - return container_of(intel_attached_encoder(connector), - struct intel_hdmi, base); + return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base); } void intel_dip_infoframe_csum(struct dip_infoframe *frame) @@ -334,6 +340,8 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; + avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode); + intel_set_infoframe(encoder, &avi_if); } @@ -754,16 +762,16 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { return true; } static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) { - struct drm_device *dev = intel_hdmi->base.base.dev; + struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); struct drm_i915_private *dev_priv = dev->dev_private; uint32_t bit; @@ -786,6 +794,9 @@ static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector, bool force) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct intel_digital_port *intel_dig_port = + hdmi_to_dig_port(intel_hdmi); + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_i915_private *dev_priv = connector->dev->dev_private; struct edid *edid; enum drm_connector_status status = connector_status_disconnected; @@ -814,6 +825,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) intel_hdmi->has_audio = (intel_hdmi->force_audio == HDMI_AUDIO_ON); + intel_encoder->type = INTEL_OUTPUT_HDMI; } return status; @@ -859,10 +871,12 @@ intel_hdmi_set_property(struct drm_connector *connector, uint64_t val) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct intel_digital_port *intel_dig_port = + hdmi_to_dig_port(intel_hdmi); struct drm_i915_private *dev_priv = connector->dev->dev_private; int ret; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; @@ -898,8 +912,8 @@ intel_hdmi_set_property(struct drm_connector *connector, return -EINVAL; done: - if (intel_hdmi->base.base.crtc) { - struct drm_crtc *crtc = intel_hdmi->base.base.crtc; + if (intel_dig_port->base.base.crtc) { + struct drm_crtc *crtc = intel_dig_port->base.base.crtc; intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); } @@ -914,12 +928,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector) kfree(connector); } -static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { - .mode_fixup = intel_hdmi_mode_fixup, - .mode_set = intel_ddi_mode_set, - .disable = intel_encoder_noop, -}; - static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { .mode_fixup = intel_hdmi_mode_fixup, .mode_set = intel_hdmi_mode_set, @@ -951,43 +959,24 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c intel_attach_broadcast_rgb_property(connector); } -void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) +void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, + struct intel_connector *intel_connector) { + struct drm_connector *connector = &intel_connector->base; + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; + struct intel_encoder *intel_encoder = &intel_dig_port->base; + struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_connector *connector; - struct intel_encoder *intel_encoder; - struct intel_connector *intel_connector; - struct intel_hdmi *intel_hdmi; - - intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL); - if (!intel_hdmi) - return; - - intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); - if (!intel_connector) { - kfree(intel_hdmi); - return; - } - - intel_encoder = &intel_hdmi->base; - drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, - DRM_MODE_ENCODER_TMDS); + enum port port = intel_dig_port->port; - connector = &intel_connector->base; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); - intel_encoder->type = INTEL_OUTPUT_HDMI; - connector->polled = DRM_CONNECTOR_POLL_HPD; connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); - intel_encoder->cloneable = false; - - intel_hdmi->ddi_port = port; switch (port) { case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; @@ -1007,8 +996,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) BUG(); } - intel_hdmi->sdvox_reg = sdvox_reg; - if (!HAS_PCH_SPLIT(dev)) { intel_hdmi->write_infoframe = g4x_write_infoframe; intel_hdmi->set_infoframes = g4x_set_infoframes; @@ -1026,21 +1013,10 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) intel_hdmi->set_infoframes = cpt_set_infoframes; } - if (IS_HASWELL(dev)) { - intel_encoder->enable = intel_enable_ddi; - intel_encoder->disable = intel_disable_ddi; - intel_encoder->get_hw_state = intel_ddi_get_hw_state; - drm_encoder_helper_add(&intel_encoder->base, - &intel_hdmi_helper_funcs_hsw); - } else { - intel_encoder->enable = intel_enable_hdmi; - intel_encoder->disable = intel_disable_hdmi; - intel_encoder->get_hw_state = intel_hdmi_get_hw_state; - drm_encoder_helper_add(&intel_encoder->base, - &intel_hdmi_helper_funcs); - } - intel_connector->get_hw_state = intel_connector_get_hw_state; - + if (IS_HASWELL(dev)) + intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; + else + intel_connector->get_hw_state = intel_connector_get_hw_state; intel_hdmi_add_properties(intel_hdmi, connector); @@ -1056,3 +1032,42 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } } + +void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) +{ + struct intel_digital_port *intel_dig_port; + struct intel_encoder *intel_encoder; + struct drm_encoder *encoder; + struct intel_connector *intel_connector; + + intel_dig_port = kzalloc(sizeof(struct intel_digital_port), GFP_KERNEL); + if (!intel_dig_port) + return; + + intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); + if (!intel_connector) { + kfree(intel_dig_port); + return; + } + + intel_encoder = &intel_dig_port->base; + encoder = &intel_encoder->base; + + drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); + + intel_encoder->enable = intel_enable_hdmi; + intel_encoder->disable = intel_disable_hdmi; + intel_encoder->get_hw_state = intel_hdmi_get_hw_state; + + intel_encoder->type = INTEL_OUTPUT_HDMI; + intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + intel_encoder->cloneable = false; + + intel_dig_port->port = port; + intel_dig_port->hdmi.sdvox_reg = sdvox_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 c2c6dbc..3ef5af1 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -432,7 +432,7 @@ timeout: I915_WRITE(GMBUS0 + reg_offset, 0); /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ - bus->force_bit = true; + bus->force_bit = 1; ret = i2c_bit_algo.master_xfer(adapter, msgs, num); out: @@ -491,7 +491,7 @@ int intel_setup_gmbus(struct drm_device *dev) /* gmbus seems to be broken on i830 */ if (IS_I830(dev)) - bus->force_bit = true; + bus->force_bit = 1; intel_gpio_setup(bus, port); @@ -532,7 +532,10 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) { struct intel_gmbus *bus = to_intel_gmbus(adapter); - bus->force_bit = force_bit; + bus->force_bit += force_bit ? 1 : -1; + DRM_DEBUG_KMS("%sabling bit-banging on %s. force bit now %d\n", + force_bit ? "en" : "dis", adapter->name, + bus->force_bit); } void intel_teardown_gmbus(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index edba93b..b9a660a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -40,28 +40,30 @@ #include <linux/acpi.h> /* Private structure for the integrated LVDS support */ -struct intel_lvds { - struct intel_encoder base; +struct intel_lvds_connector { + struct intel_connector base; - struct edid *edid; + struct notifier_block lid_notifier; +}; + +struct intel_lvds_encoder { + struct intel_encoder base; - int fitting_mode; u32 pfit_control; u32 pfit_pgm_ratios; bool pfit_dirty; - struct drm_display_mode *fixed_mode; + struct intel_lvds_connector *attached_connector; }; -static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder) +static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder) { - return container_of(encoder, struct intel_lvds, base.base); + return container_of(encoder, struct intel_lvds_encoder, base.base); } -static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) +static struct intel_lvds_connector *to_lvds_connector(struct drm_connector *connector) { - return container_of(intel_attached_encoder(connector), - struct intel_lvds, base); + return container_of(connector, struct intel_lvds_connector, base.base); } static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, @@ -96,7 +98,7 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, static void intel_enable_lvds(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; - struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct drm_i915_private *dev_priv = dev->dev_private; u32 ctl_reg, lvds_reg, stat_reg; @@ -113,7 +115,7 @@ static void intel_enable_lvds(struct intel_encoder *encoder) I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); - if (intel_lvds->pfit_dirty) { + if (lvds_encoder->pfit_dirty) { /* * Enable automatic panel scaling so that non-native modes * fill the screen. The panel fitter should only be @@ -121,12 +123,12 @@ static void intel_enable_lvds(struct intel_encoder *encoder) * register description and PRM. */ DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - intel_lvds->pfit_control, - intel_lvds->pfit_pgm_ratios); + lvds_encoder->pfit_control, + lvds_encoder->pfit_pgm_ratios); - I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); - intel_lvds->pfit_dirty = false; + I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control); + lvds_encoder->pfit_dirty = false; } I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); @@ -140,7 +142,7 @@ static void intel_enable_lvds(struct intel_encoder *encoder) static void intel_disable_lvds(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; - struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct drm_i915_private *dev_priv = dev->dev_private; u32 ctl_reg, lvds_reg, stat_reg; @@ -160,9 +162,9 @@ static void intel_disable_lvds(struct intel_encoder *encoder) if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); - if (intel_lvds->pfit_control) { + if (lvds_encoder->pfit_control) { I915_WRITE(PFIT_CONTROL, 0); - intel_lvds->pfit_dirty = true; + lvds_encoder->pfit_dirty = true; } I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); @@ -172,8 +174,8 @@ static void intel_disable_lvds(struct intel_encoder *encoder) static int intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct intel_lvds *intel_lvds = intel_attached_lvds(connector); - struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; if (mode->hdisplay > fixed_mode->hdisplay) return MODE_PANEL; @@ -249,8 +251,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds *intel_lvds = to_intel_lvds(encoder); - struct intel_crtc *intel_crtc = intel_lvds->base.new_crtc; + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); + struct intel_connector *intel_connector = + &lvds_encoder->attached_connector->base; + struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; int pipe; @@ -260,7 +264,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, return false; } - if (intel_encoder_check_is_cloned(&intel_lvds->base)) + if (intel_encoder_check_is_cloned(&lvds_encoder->base)) return false; /* @@ -269,10 +273,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode); + intel_fixed_panel_mode(intel_connector->panel.fixed_mode, + adjusted_mode); if (HAS_PCH_SPLIT(dev)) { - intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, + intel_pch_panel_fitting(dev, + intel_connector->panel.fitting_mode, mode, adjusted_mode); return true; } @@ -298,7 +304,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, drm_mode_set_crtcinfo(adjusted_mode, 0); - switch (intel_lvds->fitting_mode) { + switch (intel_connector->panel.fitting_mode) { case DRM_MODE_SCALE_CENTER: /* * For centered modes, we have to calculate border widths & @@ -396,11 +402,11 @@ out: if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; - if (pfit_control != intel_lvds->pfit_control || - pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) { - intel_lvds->pfit_control = pfit_control; - intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; - intel_lvds->pfit_dirty = true; + if (pfit_control != lvds_encoder->pfit_control || + pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { + lvds_encoder->pfit_control = pfit_control; + lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; + lvds_encoder->pfit_dirty = true; } dev_priv->lvds_border_bits = border; @@ -449,14 +455,15 @@ intel_lvds_detect(struct drm_connector *connector, bool force) */ static int intel_lvds_get_modes(struct drm_connector *connector) { - struct intel_lvds *intel_lvds = intel_attached_lvds(connector); + struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector); struct drm_device *dev = connector->dev; struct drm_display_mode *mode; - if (intel_lvds->edid) - return drm_add_edid_modes(connector, intel_lvds->edid); + /* use cached edid if we have one */ + if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) + return drm_add_edid_modes(connector, lvds_connector->base.edid); - mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); + mode = drm_mode_duplicate(dev, lvds_connector->base.panel.fixed_mode); if (mode == NULL) return 0; @@ -496,10 +503,11 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = { static int intel_lid_notify(struct notifier_block *nb, unsigned long val, void *unused) { - struct drm_i915_private *dev_priv = - container_of(nb, struct drm_i915_private, lid_notifier); - struct drm_device *dev = dev_priv->dev; - struct drm_connector *connector = dev_priv->int_lvds_connector; + struct intel_lvds_connector *lvds_connector = + container_of(nb, struct intel_lvds_connector, lid_notifier); + struct drm_connector *connector = &lvds_connector->base.base; + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; if (dev->switch_power_state != DRM_SWITCH_POWER_ON) return NOTIFY_OK; @@ -508,9 +516,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, * check and update the status of LVDS connector after receiving * the LID nofication event. */ - if (connector) - connector->status = connector->funcs->detect(connector, - false); + connector->status = connector->funcs->detect(connector, false); /* Don't force modeset on machines where it causes a GPU lockup */ if (dmi_check_system(intel_no_modeset_on_lid)) @@ -526,7 +532,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, dev_priv->modeset_on_lid = 0; mutex_lock(&dev->mode_config.mutex); - intel_modeset_check_state(dev); + intel_modeset_setup_hw_state(dev, true); mutex_unlock(&dev->mode_config.mutex); return NOTIFY_OK; @@ -541,13 +547,18 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, */ static void intel_lvds_destroy(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_lvds_connector *lvds_connector = + to_lvds_connector(connector); - intel_panel_destroy_backlight(dev); + if (lvds_connector->lid_notifier.notifier_call) + acpi_lid_notifier_unregister(&lvds_connector->lid_notifier); + + 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); - if (dev_priv->lid_notifier.notifier_call) - acpi_lid_notifier_unregister(&dev_priv->lid_notifier); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(connector); @@ -557,22 +568,24 @@ static int intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { - struct intel_lvds *intel_lvds = intel_attached_lvds(connector); + struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; if (property == dev->mode_config.scaling_mode_property) { - struct drm_crtc *crtc = intel_lvds->base.base.crtc; + struct drm_crtc *crtc; if (value == DRM_MODE_SCALE_NONE) { DRM_DEBUG_KMS("no scaling not supported\n"); return -EINVAL; } - if (intel_lvds->fitting_mode == value) { + if (intel_connector->panel.fitting_mode == value) { /* the LVDS scaling property is not changed */ return 0; } - intel_lvds->fitting_mode = value; + intel_connector->panel.fitting_mode = value; + + crtc = intel_attached_encoder(connector)->base.crtc; if (crtc && crtc->enabled) { /* * If the CRTC is enabled, the display will be changed @@ -912,12 +925,15 @@ static bool intel_lvds_supported(struct drm_device *dev) bool intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds *intel_lvds; + struct intel_lvds_encoder *lvds_encoder; struct intel_encoder *intel_encoder; + struct intel_lvds_connector *lvds_connector; struct intel_connector *intel_connector; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_display_mode *scan; /* *modes, *bios_mode; */ + struct drm_display_mode *fixed_mode = NULL; + struct edid *edid; struct drm_crtc *crtc; u32 lvds; int pipe; @@ -945,23 +961,25 @@ bool intel_lvds_init(struct drm_device *dev) } } - intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); - if (!intel_lvds) { + lvds_encoder = kzalloc(sizeof(struct intel_lvds_encoder), GFP_KERNEL); + if (!lvds_encoder) return false; - } - intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); - if (!intel_connector) { - kfree(intel_lvds); + lvds_connector = kzalloc(sizeof(struct intel_lvds_connector), GFP_KERNEL); + if (!lvds_connector) { + kfree(lvds_encoder); return false; } + lvds_encoder->attached_connector = lvds_connector; + if (!HAS_PCH_SPLIT(dev)) { - intel_lvds->pfit_control = I915_READ(PFIT_CONTROL); + lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL); } - intel_encoder = &intel_lvds->base; + intel_encoder = &lvds_encoder->base; encoder = &intel_encoder->base; + intel_connector = &lvds_connector->base; connector = &intel_connector->base; drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, DRM_MODE_CONNECTOR_LVDS); @@ -993,14 +1011,10 @@ bool intel_lvds_init(struct drm_device *dev) /* create the scaling mode property */ drm_mode_create_scaling_mode_property(dev); - /* - * the initial panel fitting mode will be FULL_SCREEN. - */ - - drm_connector_attach_property(&intel_connector->base, + drm_object_attach_property(&connector->base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_ASPECT); - intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT; + intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT; /* * LVDS discovery: * 1) check for EDID on DDC @@ -1015,20 +1029,21 @@ bool intel_lvds_init(struct drm_device *dev) * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - intel_lvds->edid = drm_get_edid(connector, - intel_gmbus_get_adapter(dev_priv, - pin)); - if (intel_lvds->edid) { - if (drm_add_edid_modes(connector, - intel_lvds->edid)) { + edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin)); + if (edid) { + if (drm_add_edid_modes(connector, edid)) { drm_mode_connector_update_edid_property(connector, - intel_lvds->edid); + edid); } else { - kfree(intel_lvds->edid); - intel_lvds->edid = NULL; + kfree(edid); + edid = ERR_PTR(-EINVAL); } + } else { + edid = ERR_PTR(-ENOENT); } - if (!intel_lvds->edid) { + lvds_connector->base.edid = edid; + + if (IS_ERR_OR_NULL(edid)) { /* Didn't get an EDID, so * Set wide sync ranges so we get all modes * handed to valid_mode for checking @@ -1041,22 +1056,26 @@ bool intel_lvds_init(struct drm_device *dev) list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { - intel_lvds->fixed_mode = - drm_mode_duplicate(dev, scan); - intel_find_lvds_downclock(dev, - intel_lvds->fixed_mode, - connector); - goto out; + DRM_DEBUG_KMS("using preferred mode from EDID: "); + drm_mode_debug_printmodeline(scan); + + fixed_mode = drm_mode_duplicate(dev, scan); + if (fixed_mode) { + intel_find_lvds_downclock(dev, fixed_mode, + connector); + goto out; + } } } /* Failed to get EDID, what about VBT? */ if (dev_priv->lfp_lvds_vbt_mode) { - intel_lvds->fixed_mode = - drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (intel_lvds->fixed_mode) { - intel_lvds->fixed_mode->type |= - DRM_MODE_TYPE_PREFERRED; + DRM_DEBUG_KMS("using mode from VBT: "); + drm_mode_debug_printmodeline(dev_priv->lfp_lvds_vbt_mode); + + fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (fixed_mode) { + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; } } @@ -1076,16 +1095,17 @@ bool intel_lvds_init(struct drm_device *dev) crtc = intel_get_crtc_for_pipe(dev, pipe); if (crtc && (lvds & LVDS_PORT_EN)) { - intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc); - if (intel_lvds->fixed_mode) { - intel_lvds->fixed_mode->type |= - DRM_MODE_TYPE_PREFERRED; + fixed_mode = intel_crtc_mode_get(dev, crtc); + if (fixed_mode) { + DRM_DEBUG_KMS("using current (BIOS) mode: "); + drm_mode_debug_printmodeline(fixed_mode); + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; } } /* If we still don't have a mode after all that, give up. */ - if (!intel_lvds->fixed_mode) + if (!fixed_mode) goto failed; out: @@ -1100,16 +1120,15 @@ out: I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); } - dev_priv->lid_notifier.notifier_call = intel_lid_notify; - if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) { + lvds_connector->lid_notifier.notifier_call = intel_lid_notify; + if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { DRM_DEBUG_KMS("lid notifier registration failed\n"); - dev_priv->lid_notifier.notifier_call = NULL; + lvds_connector->lid_notifier.notifier_call = NULL; } - /* keep the LVDS connector */ - dev_priv->int_lvds_connector = connector; drm_sysfs_connector_add(connector); - intel_panel_setup_backlight(dev); + intel_panel_init(&intel_connector->panel, fixed_mode); + intel_panel_setup_backlight(connector); return true; @@ -1117,7 +1136,9 @@ failed: DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); drm_connector_cleanup(connector); drm_encoder_cleanup(encoder); - kfree(intel_lvds); - kfree(intel_connector); + if (fixed_mode) + drm_mode_destroy(dev, fixed_mode); + kfree(lvds_encoder); + kfree(lvds_connector); return false; } diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index cabd84b..b00f1c8 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -45,7 +45,6 @@ int intel_connector_update_modes(struct drm_connector *connector, drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); drm_edid_to_eld(connector, edid); - kfree(edid); return ret; } @@ -61,12 +60,16 @@ int intel_ddc_get_modes(struct drm_connector *connector, struct i2c_adapter *adapter) { struct edid *edid; + int ret; edid = drm_get_edid(connector, adapter); if (!edid) return 0; - return intel_connector_update_modes(connector, edid); + ret = intel_connector_update_modes(connector, edid); + kfree(edid); + + return ret; } static const struct drm_prop_enum_list force_audio_names[] = { @@ -94,7 +97,7 @@ intel_attach_force_audio_property(struct drm_connector *connector) dev_priv->force_audio_property = prop; } - drm_connector_attach_property(connector, prop, 0); + drm_object_attach_property(&connector->base, prop, 0); } static const struct drm_prop_enum_list broadcast_rgb_names[] = { @@ -121,5 +124,5 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector) dev_priv->broadcast_rgb_property = prop; } - drm_connector_attach_property(connector, prop, 0); + drm_object_attach_property(&connector->base, prop, 0); } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 5530413..7741c22 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -154,6 +154,8 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) struct opregion_asle __iomem *asle = dev_priv->opregion.asle; u32 max; + DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); + if (!(bclp & ASLE_BCLP_VALID)) return ASLE_BACKLIGHT_FAILED; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e2aacd3..bee8cb6 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -130,32 +130,34 @@ static int is_backlight_combination_mode(struct drm_device *dev) return 0; } -static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) +static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; u32 val; /* Restore the CTL value if it lost, e.g. GPU reset */ if (HAS_PCH_SPLIT(dev_priv->dev)) { val = I915_READ(BLC_PWM_PCH_CTL2); - if (dev_priv->saveBLC_PWM_CTL2 == 0) { - dev_priv->saveBLC_PWM_CTL2 = val; + if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { + dev_priv->regfile.saveBLC_PWM_CTL2 = val; } else if (val == 0) { - I915_WRITE(BLC_PWM_PCH_CTL2, - dev_priv->saveBLC_PWM_CTL2); - val = dev_priv->saveBLC_PWM_CTL2; + val = dev_priv->regfile.saveBLC_PWM_CTL2; + I915_WRITE(BLC_PWM_PCH_CTL2, val); } } else { val = I915_READ(BLC_PWM_CTL); - if (dev_priv->saveBLC_PWM_CTL == 0) { - dev_priv->saveBLC_PWM_CTL = val; - dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { + dev_priv->regfile.saveBLC_PWM_CTL = val; + if (INTEL_INFO(dev)->gen >= 4) + dev_priv->regfile.saveBLC_PWM_CTL2 = + I915_READ(BLC_PWM_CTL2); } else if (val == 0) { - I915_WRITE(BLC_PWM_CTL, - dev_priv->saveBLC_PWM_CTL); - I915_WRITE(BLC_PWM_CTL2, - dev_priv->saveBLC_PWM_CTL2); - val = dev_priv->saveBLC_PWM_CTL; + val = dev_priv->regfile.saveBLC_PWM_CTL; + I915_WRITE(BLC_PWM_CTL, val); + if (INTEL_INFO(dev)->gen >= 4) + I915_WRITE(BLC_PWM_CTL2, + dev_priv->regfile.saveBLC_PWM_CTL2); } } @@ -164,10 +166,9 @@ static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) static u32 _intel_panel_get_max_backlight(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 max; - max = i915_read_blc_pwm_ctl(dev_priv); + max = i915_read_blc_pwm_ctl(dev); if (HAS_PCH_SPLIT(dev)) { max >>= 16; @@ -275,7 +276,7 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level } tmp = I915_READ(BLC_PWM_CTL); - if (INTEL_INFO(dev)->gen < 4) + if (INTEL_INFO(dev)->gen < 4) level <<= 1; tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; I915_WRITE(BLC_PWM_CTL, tmp | level); @@ -374,26 +375,23 @@ static void intel_panel_init_backlight(struct drm_device *dev) enum drm_connector_status intel_panel_detect(struct drm_device *dev) { -#if 0 struct drm_i915_private *dev_priv = dev->dev_private; -#endif - - if (i915_panel_ignore_lid) - return i915_panel_ignore_lid > 0 ? - connector_status_connected : - connector_status_disconnected; - /* opregion lid state on HP 2540p is wrong at boot up, - * appears to be either the BIOS or Linux ACPI fault */ -#if 0 /* Assume that the BIOS does not lie through the OpRegion... */ - if (dev_priv->opregion.lid_state) + if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { return ioread32(dev_priv->opregion.lid_state) & 0x1 ? connector_status_connected : connector_status_disconnected; -#endif + } - return connector_status_unknown; + switch (i915_panel_ignore_lid) { + case -2: + return connector_status_connected; + case -1: + return connector_status_disconnected; + default: + return connector_status_unknown; + } } #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE @@ -416,21 +414,14 @@ static const struct backlight_ops intel_panel_bl_ops = { .get_brightness = intel_panel_get_brightness, }; -int intel_panel_setup_backlight(struct drm_device *dev) +int intel_panel_setup_backlight(struct drm_connector *connector) { + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct backlight_properties props; - struct drm_connector *connector; intel_panel_init_backlight(dev); - if (dev_priv->int_lvds_connector) - connector = dev_priv->int_lvds_connector; - else if (dev_priv->int_edp_connector) - connector = dev_priv->int_edp_connector; - else - return -ENODEV; - memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = _intel_panel_get_max_backlight(dev); @@ -460,9 +451,9 @@ void intel_panel_destroy_backlight(struct drm_device *dev) backlight_device_unregister(dev_priv->backlight); } #else -int intel_panel_setup_backlight(struct drm_device *dev) +int intel_panel_setup_backlight(struct drm_connector *connector) { - intel_panel_init_backlight(dev); + intel_panel_init_backlight(connector->dev); return 0; } @@ -471,3 +462,20 @@ void intel_panel_destroy_backlight(struct drm_device *dev) return; } #endif + +int intel_panel_init(struct intel_panel *panel, + struct drm_display_mode *fixed_mode) +{ + panel->fixed_mode = fixed_mode; + + return 0; +} + +void intel_panel_fini(struct intel_panel *panel) +{ + struct intel_connector *intel_connector = + container_of(panel, struct intel_connector, panel); + + if (panel->fixed_mode) + drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); +} diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 442968f..496caa7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1325,10 +1325,11 @@ static void valleyview_update_wm(struct drm_device *dev) (planeb_wm << DSPFW_PLANEB_SHIFT) | planea_wm); I915_WRITE(DSPFW2, - (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) | (cursora_wm << DSPFW_CURSORA_SHIFT)); I915_WRITE(DSPFW3, - (I915_READ(DSPFW3) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT))); + (I915_READ(DSPFW3) & ~DSPFW_CURSOR_SR_MASK) | + (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } static void g4x_update_wm(struct drm_device *dev) @@ -1374,11 +1375,11 @@ static void g4x_update_wm(struct drm_device *dev) (planeb_wm << DSPFW_PLANEB_SHIFT) | planea_wm); I915_WRITE(DSPFW2, - (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) | (cursora_wm << DSPFW_CURSORA_SHIFT)); /* HPLL off in SR has some issues on G4x... disable it */ I915_WRITE(DSPFW3, - (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | + (I915_READ(DSPFW3) & ~(DSPFW_HPLL_SR_EN | DSPFW_CURSOR_SR_MASK)) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } @@ -1468,9 +1469,12 @@ static void i9xx_update_wm(struct drm_device *dev) fifo_size = dev_priv->display.get_fifo_size(dev, 0); crtc = intel_get_crtc_for_plane(dev, 0); if (crtc->enabled && crtc->fb) { + int cpp = crtc->fb->bits_per_pixel / 8; + if (IS_GEN2(dev)) + cpp = 4; + planea_wm = intel_calculate_wm(crtc->mode.clock, - wm_info, fifo_size, - crtc->fb->bits_per_pixel / 8, + wm_info, fifo_size, cpp, latency_ns); enabled = crtc; } else @@ -1479,9 +1483,12 @@ static void i9xx_update_wm(struct drm_device *dev) fifo_size = dev_priv->display.get_fifo_size(dev, 1); crtc = intel_get_crtc_for_plane(dev, 1); if (crtc->enabled && crtc->fb) { + int cpp = crtc->fb->bits_per_pixel / 8; + if (IS_GEN2(dev)) + cpp = 4; + planeb_wm = intel_calculate_wm(crtc->mode.clock, - wm_info, fifo_size, - crtc->fb->bits_per_pixel / 8, + wm_info, fifo_size, cpp, latency_ns); if (enabled == NULL) enabled = crtc; @@ -1571,8 +1578,7 @@ static void i830_update_wm(struct drm_device *dev) planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info, dev_priv->display.get_fifo_size(dev, 0), - crtc->fb->bits_per_pixel / 8, - latency_ns); + 4, latency_ns); fwater_lo = I915_READ(FW_BLC) & ~0xfff; fwater_lo |= (3<<8) | planea_wm; @@ -2323,7 +2329,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val) struct drm_i915_private *dev_priv = dev->dev_private; u32 limits = gen6_rps_limits(dev_priv, &val); - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); @@ -2398,12 +2404,12 @@ static void gen6_enable_rps(struct drm_device *dev) struct intel_ring_buffer *ring; u32 rp_state_cap; u32 gt_perf_status; - u32 pcu_mbox, rc6_mask = 0; + u32 rc6vids, pcu_mbox, rc6_mask = 0; u32 gtfifodbg; int rc6_mode; - int i; + int i, ret; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); /* Here begins a magic sequence of register writes to enable * auto-downclocking. @@ -2497,30 +2503,16 @@ static void gen6_enable_rps(struct drm_device *dev) GEN6_RP_UP_BUSY_AVG | (IS_HASWELL(dev) ? GEN7_RP_DOWN_IDLE_AVG : GEN6_RP_DOWN_IDLE_CONT)); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); - - I915_WRITE(GEN6_PCODE_DATA, 0); - I915_WRITE(GEN6_PCODE_MAILBOX, - GEN6_PCODE_READY | - GEN6_PCODE_WRITE_MIN_FREQ_TABLE); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); - - /* Check for overclock support */ - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); - pcu_mbox = I915_READ(GEN6_PCODE_DATA); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); - if (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); + ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0); + 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); + } + } else { + DRM_DEBUG_DRIVER("Failed to set the min frequency\n"); } gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8); @@ -2534,6 +2526,20 @@ static void gen6_enable_rps(struct drm_device *dev) /* enable all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); + rc6vids = 0; + ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); + if (IS_GEN6(dev) && ret) { + DRM_DEBUG_DRIVER("Couldn't check for BIOS workaround\n"); + } else if (IS_GEN6(dev) && (GEN6_DECODE_RC6_VID(rc6vids & 0xff) < 450)) { + DRM_DEBUG_DRIVER("You should update your BIOS. Correcting minimum rc6 voltage (%dmV->%dmV)\n", + GEN6_DECODE_RC6_VID(rc6vids & 0xff), 450); + rc6vids &= 0xffff00; + rc6vids |= GEN6_ENCODE_RC6_VID(450); + ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_RC6VIDS, rc6vids); + if (ret) + DRM_ERROR("Couldn't fix incorrect rc6 voltage\n"); + } + gen6_gt_force_wake_put(dev_priv); } @@ -2541,10 +2547,11 @@ 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, ia_freq, max_ia_freq; + int gpu_freq; + unsigned int ia_freq, max_ia_freq; int scaling_factor = 180; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); max_ia_freq = cpufreq_quick_get_max(0); /* @@ -2575,17 +2582,11 @@ static void gen6_update_ring_freq(struct drm_device *dev) 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; - I915_WRITE(GEN6_PCODE_DATA, - (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) | - gpu_freq); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | - GEN6_PCODE_WRITE_MIN_FREQ_TABLE); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & - GEN6_PCODE_READY) == 0, 10)) { - DRM_ERROR("pcode write of freq table timed out\n"); - continue; - } + sandybridge_pcode_write(dev_priv, + GEN6_PCODE_WRITE_MIN_FREQ_TABLE, + ia_freq | gpu_freq); } } @@ -2593,16 +2594,16 @@ void ironlake_teardown_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->renderctx) { - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; + if (dev_priv->ips.renderctx) { + i915_gem_object_unpin(dev_priv->ips.renderctx); + drm_gem_object_unreference(&dev_priv->ips.renderctx->base); + dev_priv->ips.renderctx = NULL; } - if (dev_priv->pwrctx) { - i915_gem_object_unpin(dev_priv->pwrctx); - drm_gem_object_unreference(&dev_priv->pwrctx->base); - dev_priv->pwrctx = NULL; + if (dev_priv->ips.pwrctx) { + i915_gem_object_unpin(dev_priv->ips.pwrctx); + drm_gem_object_unreference(&dev_priv->ips.pwrctx->base); + dev_priv->ips.pwrctx = NULL; } } @@ -2628,14 +2629,14 @@ static int ironlake_setup_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->renderctx == NULL) - dev_priv->renderctx = intel_alloc_context_page(dev); - if (!dev_priv->renderctx) + if (dev_priv->ips.renderctx == NULL) + dev_priv->ips.renderctx = intel_alloc_context_page(dev); + if (!dev_priv->ips.renderctx) return -ENOMEM; - if (dev_priv->pwrctx == NULL) - dev_priv->pwrctx = intel_alloc_context_page(dev); - if (!dev_priv->pwrctx) { + if (dev_priv->ips.pwrctx == NULL) + dev_priv->ips.pwrctx = intel_alloc_context_page(dev); + if (!dev_priv->ips.pwrctx) { ironlake_teardown_rc6(dev); return -ENOMEM; } @@ -2647,6 +2648,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + bool was_interruptible; int ret; /* rc6 disabled by default due to repeated reports of hanging during @@ -2661,6 +2663,9 @@ static void ironlake_enable_rc6(struct drm_device *dev) if (ret) return; + was_interruptible = dev_priv->mm.interruptible; + dev_priv->mm.interruptible = false; + /* * GPU can automatically power down the render unit if given a page * to save state. @@ -2668,12 +2673,13 @@ static void ironlake_enable_rc6(struct drm_device *dev) ret = intel_ring_begin(ring, 6); if (ret) { ironlake_teardown_rc6(dev); + dev_priv->mm.interruptible = was_interruptible; return; } intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); intel_ring_emit(ring, MI_SET_CONTEXT); - intel_ring_emit(ring, dev_priv->renderctx->gtt_offset | + intel_ring_emit(ring, dev_priv->ips.renderctx->gtt_offset | MI_MM_SPACE_GTT | MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN | @@ -2688,14 +2694,15 @@ static void ironlake_enable_rc6(struct drm_device *dev) * does an implicit flush, combined with MI_FLUSH above, it should be * safe to assume that renderctx is valid */ - ret = intel_wait_ring_idle(ring); + ret = intel_ring_idle(ring); + dev_priv->mm.interruptible = was_interruptible; if (ret) { DRM_ERROR("failed to enable ironlake power power savings\n"); ironlake_teardown_rc6(dev); return; } - I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); + I915_WRITE(PWRCTXA, dev_priv->ips.pwrctx->gtt_offset | PWRCTX_EN); I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); } @@ -3304,37 +3311,72 @@ static void intel_init_emon(struct drm_device *dev) void intel_disable_gt_powersave(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + if (IS_IRONLAKE_M(dev)) { ironlake_disable_drps(dev); ironlake_disable_rc6(dev); } else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) { + cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); + mutex_lock(&dev_priv->rps.hw_lock); gen6_disable_rps(dev); + mutex_unlock(&dev_priv->rps.hw_lock); } } +static void intel_gen6_powersave_work(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, + rps.delayed_resume_work.work); + struct drm_device *dev = dev_priv->dev; + + mutex_lock(&dev_priv->rps.hw_lock); + gen6_enable_rps(dev); + gen6_update_ring_freq(dev); + mutex_unlock(&dev_priv->rps.hw_lock); +} + void intel_enable_gt_powersave(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); ironlake_enable_rc6(dev); intel_init_emon(dev); } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) { - gen6_enable_rps(dev); - gen6_update_ring_freq(dev); + /* + * PCU communication is slow and this doesn't need to be + * done at any specific time, so do this out of our fast path + * to make resume and init faster. + */ + schedule_delayed_work(&dev_priv->rps.delayed_resume_work, + round_jiffies_up_relative(HZ)); } } +static void ibx_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); +} + static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; /* Required for FBC */ - dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | - DPFCRUNIT_CLOCK_GATE_DISABLE | - DPFDUNIT_CLOCK_GATE_DISABLE; - /* Required for CxSR */ - dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; + dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE | + ILK_DPFCUNIT_CLOCK_GATE_DISABLE | + ILK_DPFDUNIT_CLOCK_GATE_ENABLE; I915_WRITE(PCH_3DCGDIS0, MARIUNIT_CLOCK_GATE_DISABLE | @@ -3342,8 +3384,6 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(PCH_3DCGDIS1, VFMUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - /* * According to the spec the following bits should be set in * order to enable memory self-refresh @@ -3354,9 +3394,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DISPLAY_CHICKEN2, (I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_DPARB_GATE | ILK_VSDPFD_FULL)); - I915_WRITE(ILK_DSPCLK_GATE, - (I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE)); + dspclk_gate |= ILK_DPARBUNIT_CLOCK_GATE_ENABLE; I915_WRITE(DISP_ARB_CTL, (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); @@ -3378,28 +3416,56 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DISPLAY_CHICKEN2, I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_DPARB_GATE); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPFC_DIS1 | - ILK_DPFC_DIS2 | - ILK_CLK_FBC); } + I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate); + I915_WRITE(ILK_DISPLAY_CHICKEN2, I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_ELPIN_409_SELECT); I915_WRITE(_3D_CHICKEN2, _3D_CHICKEN2_WM_READ_PIPELINED << 16 | _3D_CHICKEN2_WM_READ_PIPELINED); + + /* WaDisableRenderCachePipelinedFlush */ + I915_WRITE(CACHE_MODE_0, + _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); + + ibx_init_clock_gating(dev); +} + +static void cpt_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | + DPLS_EDP_PPS_FIX_DIS); + /* 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); + /* WADP0ClockGatingDisable */ + for_each_pipe(pipe) { + I915_WRITE(TRANS_CHICKEN1(pipe), + TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); + } } static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate); I915_WRITE(ILK_DISPLAY_CHICKEN2, I915_READ(ILK_DISPLAY_CHICKEN2) | @@ -3454,11 +3520,12 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DISPLAY_CHICKEN2, I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_DPARB_GATE | ILK_VSDPFD_FULL); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE | - ILK_DPFD_CLK_GATE); + I915_WRITE(ILK_DSPCLK_GATE_D, + I915_READ(ILK_DSPCLK_GATE_D) | + ILK_DPARBUNIT_CLOCK_GATE_ENABLE | + ILK_DPFDUNIT_CLOCK_GATE_ENABLE); + /* WaMbcDriverBootEnable */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); @@ -3473,6 +3540,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) * platforms I checked have a 0 for this. (Maybe BIOS overrides?) */ I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_DISABLE(0xffff)); I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_GT_MODE_HI)); + + cpt_init_clock_gating(dev); } static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) @@ -3487,13 +3556,24 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) I915_WRITE(GEN7_FF_THREAD_MODE, reg); } +static void lpt_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * TODO: this bit should only be enabled when really needed, then + * disabled when not needed anymore in order to save power. + */ + if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) + I915_WRITE(SOUTH_DSPCLK_GATE_D, + I915_READ(SOUTH_DSPCLK_GATE_D) | + PCH_LP_PARTITION_LEVEL_DISABLE); +} + static void haswell_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); @@ -3504,12 +3584,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) */ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - - I915_WRITE(IVB_CHICKEN3, - CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | - CHICKEN3_DGMG_DONE_FIX_DISABLE); - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); @@ -3538,6 +3612,10 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); + /* WaMbcDriverBootEnable */ + I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | + GEN6_MBCTL_ENABLE_BOOT_FETCH); + /* XXX: This is a workaround for early silicon revisions and should be * removed later. */ @@ -3547,27 +3625,38 @@ static void haswell_init_clock_gating(struct drm_device *dev) WM_DBG_DISALLOW_SPRITE | WM_DBG_DISALLOW_MAXFIFO); + lpt_init_clock_gating(dev); } static void ivybridge_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; uint32_t snpcr; - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); + + /* WaDisableEarlyCull */ + I915_WRITE(_3D_CHICKEN3, + _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + /* WaDisableBackToBackFlipFix */ I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); + /* WaDisablePSDDualDispatchEnable */ + if (IS_IVB_GT1(dev)) + I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, + _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + else + I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2, + _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); @@ -3576,7 +3665,18 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, - GEN7_WA_L3_CHICKEN_MODE); + GEN7_WA_L3_CHICKEN_MODE); + if (IS_IVB_GT1(dev)) + I915_WRITE(GEN7_ROW_CHICKEN2, + _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); + else + I915_WRITE(GEN7_ROW_CHICKEN2_GT2, + _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); + + + /* WaForceL3Serialization */ + I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & + ~L3SQ_URB_READ_CAM_MATCH_DISABLE); /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock * gating disable must be set. Failure to set it results in @@ -3607,6 +3707,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) intel_flush_display_plane(dev_priv, pipe); } + /* WaMbcDriverBootEnable */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); @@ -3620,39 +3721,59 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) snpcr &= ~GEN6_MBC_SNPCR_MASK; snpcr |= GEN6_MBC_SNPCR_MED; I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); + + cpt_init_clock_gating(dev); } static void valleyview_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); + + /* WaDisableEarlyCull */ + I915_WRITE(_3D_CHICKEN3, + _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); + /* WaDisableBackToBackFlipFix */ I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); + I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, + _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ - I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); + I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS); I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); + /* WaForceL3Serialization */ + I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & + ~L3SQ_URB_READ_CAM_MATCH_DISABLE); + + /* WaDisableDopClockGating */ + I915_WRITE(GEN7_ROW_CHICKEN2, + _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); + + /* WaForceL3Serialization */ + I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & + ~L3SQ_URB_READ_CAM_MATCH_DISABLE); + /* This is required by WaCatErrorRejectionIssue */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + /* WaMbcDriverBootEnable */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); @@ -3704,6 +3825,13 @@ static void valleyview_init_clock_gating(struct drm_device *dev) 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); } static void g4x_init_clock_gating(struct drm_device *dev) @@ -3722,6 +3850,10 @@ static void g4x_init_clock_gating(struct drm_device *dev) if (IS_GM45(dev)) dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; I915_WRITE(DSPCLK_GATE_D, dspclk_gate); + + /* WaDisableRenderCachePipelinedFlush */ + I915_WRITE(CACHE_MODE_0, + _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); } static void crestline_init_clock_gating(struct drm_device *dev) @@ -3777,44 +3909,11 @@ static void i830_init_clock_gating(struct drm_device *dev) I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); } -static void ibx_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); -} - -static void cpt_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | - DPLS_EDP_PPS_FIX_DIS); - /* Without this, mode sets may fail silently on FDI */ - for_each_pipe(pipe) - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); -} - void intel_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->display.init_clock_gating(dev); - - if (dev_priv->display.init_pch_clock_gating) - dev_priv->display.init_pch_clock_gating(dev); } /* Starting with Haswell, we have different power wells for @@ -3840,7 +3939,7 @@ void intel_init_power_wells(struct drm_device *dev) if ((well & HSW_PWR_WELL_STATE) == 0) { I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE); - if (wait_for(I915_READ(power_wells[i] & HSW_PWR_WELL_STATE), 20)) + if (wait_for((I915_READ(power_wells[i]) & HSW_PWR_WELL_STATE), 20)) DRM_ERROR("Error enabling power well %lx\n", power_wells[i]); } } @@ -3878,11 +3977,6 @@ void intel_init_pm(struct drm_device *dev) /* For FIFO watermark updates */ if (HAS_PCH_SPLIT(dev)) { - if (HAS_PCH_IBX(dev)) - dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; - else if (HAS_PCH_CPT(dev)) - dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating; - if (IS_GEN5(dev)) { if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) dev_priv->display.update_wm = ironlake_update_wm; @@ -3993,6 +4087,12 @@ static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv) DRM_ERROR("GT thread status wait timed out\n"); } +static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) +{ + I915_WRITE_NOTRACE(FORCEWAKE, 0); + POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ +} + static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { u32 forcewake_ack; @@ -4006,7 +4106,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); - I915_WRITE_NOTRACE(FORCEWAKE, 1); + I915_WRITE_NOTRACE(FORCEWAKE, FORCEWAKE_KERNEL); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), @@ -4016,6 +4116,12 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) __gen6_gt_wait_for_thread_c0(dev_priv); } +static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) +{ + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff)); + POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ +} + static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) { u32 forcewake_ack; @@ -4029,7 +4135,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); - I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1)); + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), @@ -4073,7 +4179,7 @@ static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) { - I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1)); + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); /* gen6_gt_check_fifodbg doubles as the POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); } @@ -4111,13 +4217,18 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) return ret; } +static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) +{ + I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff)); +} + static void vlv_force_wake_get(struct drm_i915_private *dev_priv) { if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 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(1)); + I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), FORCEWAKE_ACK_TIMEOUT_MS)) @@ -4128,49 +4239,89 @@ 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(1)); + I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); /* The below doubles as a POSTING_READ */ gen6_gt_check_fifodbg(dev_priv); } +void intel_gt_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_VALLEYVIEW(dev)) { + vlv_force_wake_reset(dev_priv); + } else if (INTEL_INFO(dev)->gen >= 6) { + __gen6_gt_force_wake_reset(dev_priv); + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) + __gen6_gt_force_wake_mt_reset(dev_priv); + } +} + void intel_gt_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; spin_lock_init(&dev_priv->gt_lock); + intel_gt_reset(dev); + if (IS_VALLEYVIEW(dev)) { dev_priv->gt.force_wake_get = vlv_force_wake_get; dev_priv->gt.force_wake_put = vlv_force_wake_put; - } else if (INTEL_INFO(dev)->gen >= 6) { + } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { + dev_priv->gt.force_wake_get = __gen6_gt_force_wake_mt_get; + dev_priv->gt.force_wake_put = __gen6_gt_force_wake_mt_put; + } else if (IS_GEN6(dev)) { dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get; dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put; + } + INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work, + intel_gen6_powersave_work); +} - /* IVB configs may use multi-threaded forcewake */ - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { - u32 ecobus; - - /* A small trick here - if the bios hasn't configured - * MT forcewake, and if the device is in RC6, then - * force_wake_mt_get will not wake the device and the - * ECOBUS read will return zero. Which will be - * (correctly) interpreted by the test below as MT - * forcewake being disabled. - */ - mutex_lock(&dev->struct_mutex); - __gen6_gt_force_wake_mt_get(dev_priv); - ecobus = I915_READ_NOTRACE(ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv); - mutex_unlock(&dev->struct_mutex); - - if (ecobus & FORCEWAKE_MT_ENABLE) { - DRM_DEBUG_KMS("Using MT version of forcewake\n"); - dev_priv->gt.force_wake_get = - __gen6_gt_force_wake_mt_get; - dev_priv->gt.force_wake_put = - __gen6_gt_force_wake_mt_put; - } - } +int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) +{ + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) { + DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed\n"); + return -EAGAIN; + } + + I915_WRITE(GEN6_PCODE_DATA, *val); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); + + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) { + DRM_ERROR("timeout waiting for pcode read (%d) to finish\n", mbox); + return -ETIMEDOUT; } + + *val = I915_READ(GEN6_PCODE_DATA); + I915_WRITE(GEN6_PCODE_DATA, 0); + + return 0; } +int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) +{ + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) { + DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed\n"); + return -EAGAIN; + } + + I915_WRITE(GEN6_PCODE_DATA, val); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox); + + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) { + DRM_ERROR("timeout waiting for pcode write (%d) to finish\n", mbox); + return -ETIMEDOUT; + } + + I915_WRITE(GEN6_PCODE_DATA, 0); + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ecbc5c5..2346b92 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -45,7 +45,7 @@ struct pipe_control { static inline int ring_space(struct intel_ring_buffer *ring) { - int space = (ring->head & HEAD_ADDR) - (ring->tail + 8); + int space = (ring->head & HEAD_ADDR) - (ring->tail + I915_RING_FREE_SPACE); if (space < 0) space += ring->size; return space; @@ -245,7 +245,7 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring, /* * TLB invalidate requires a post-sync write. */ - flags |= PIPE_CONTROL_QW_WRITE; + flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL; } ret = intel_ring_begin(ring, 4); @@ -555,15 +555,11 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring) static void update_mboxes(struct intel_ring_buffer *ring, - u32 seqno, - u32 mmio_offset) + u32 mmio_offset) { - intel_ring_emit(ring, MI_SEMAPHORE_MBOX | - MI_SEMAPHORE_GLOBAL_GTT | - MI_SEMAPHORE_REGISTER | - MI_SEMAPHORE_UPDATE); - intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(ring, mmio_offset); + intel_ring_emit(ring, ring->outstanding_lazy_request); } /** @@ -576,8 +572,7 @@ update_mboxes(struct intel_ring_buffer *ring, * This acts like a signal in the canonical semaphore. */ static int -gen6_add_request(struct intel_ring_buffer *ring, - u32 *seqno) +gen6_add_request(struct intel_ring_buffer *ring) { u32 mbox1_reg; u32 mbox2_reg; @@ -590,13 +585,11 @@ gen6_add_request(struct intel_ring_buffer *ring, mbox1_reg = ring->signal_mbox[0]; mbox2_reg = ring->signal_mbox[1]; - *seqno = i915_gem_next_request_seqno(ring); - - update_mboxes(ring, *seqno, mbox1_reg); - update_mboxes(ring, *seqno, mbox2_reg); + update_mboxes(ring, mbox1_reg); + update_mboxes(ring, mbox2_reg); intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, *seqno); + intel_ring_emit(ring, ring->outstanding_lazy_request); intel_ring_emit(ring, MI_USER_INTERRUPT); intel_ring_advance(ring); @@ -653,10 +646,8 @@ do { \ } while (0) static int -pc_render_add_request(struct intel_ring_buffer *ring, - u32 *result) +pc_render_add_request(struct intel_ring_buffer *ring) { - u32 seqno = i915_gem_next_request_seqno(ring); struct pipe_control *pc = ring->private; u32 scratch_addr = pc->gtt_offset + 128; int ret; @@ -677,7 +668,7 @@ pc_render_add_request(struct intel_ring_buffer *ring, PIPE_CONTROL_WRITE_FLUSH | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE); intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); + intel_ring_emit(ring, ring->outstanding_lazy_request); intel_ring_emit(ring, 0); PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; /* write to separate cachelines */ @@ -696,11 +687,10 @@ pc_render_add_request(struct intel_ring_buffer *ring, PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | PIPE_CONTROL_NOTIFY); intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); + intel_ring_emit(ring, ring->outstanding_lazy_request); intel_ring_emit(ring, 0); intel_ring_advance(ring); - *result = seqno; return 0; } @@ -888,25 +878,20 @@ bsd_ring_flush(struct intel_ring_buffer *ring, } static int -i9xx_add_request(struct intel_ring_buffer *ring, - u32 *result) +i9xx_add_request(struct intel_ring_buffer *ring) { - u32 seqno; int ret; ret = intel_ring_begin(ring, 4); if (ret) return ret; - seqno = i915_gem_next_request_seqno(ring); - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); + intel_ring_emit(ring, ring->outstanding_lazy_request); intel_ring_emit(ring, MI_USER_INTERRUPT); intel_ring_advance(ring); - *result = seqno; return 0; } @@ -964,7 +949,9 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) } static int -i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) +i965_dispatch_execbuffer(struct intel_ring_buffer *ring, + u32 offset, u32 length, + unsigned flags) { int ret; @@ -975,7 +962,7 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT | - MI_BATCH_NON_SECURE_I965); + (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_I965)); intel_ring_emit(ring, offset); intel_ring_advance(ring); @@ -984,7 +971,8 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) static int i830_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len) + u32 offset, u32 len, + unsigned flags) { int ret; @@ -993,7 +981,7 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring, return ret; intel_ring_emit(ring, MI_BATCH_BUFFER); - intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); + intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE)); intel_ring_emit(ring, offset + len - 8); intel_ring_emit(ring, 0); intel_ring_advance(ring); @@ -1003,7 +991,8 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring, static int i915_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len) + u32 offset, u32 len, + unsigned flags) { int ret; @@ -1012,7 +1001,7 @@ i915_dispatch_execbuffer(struct intel_ring_buffer *ring, return ret; intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT); - intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); + intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE)); intel_ring_advance(ring); return 0; @@ -1075,6 +1064,29 @@ err: return ret; } +static int init_phys_hws_pga(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + u32 addr; + + if (!dev_priv->status_page_dmah) { + dev_priv->status_page_dmah = + drm_pci_alloc(ring->dev, PAGE_SIZE, PAGE_SIZE); + if (!dev_priv->status_page_dmah) + return -ENOMEM; + } + + addr = dev_priv->status_page_dmah->busaddr; + if (INTEL_INFO(ring->dev)->gen >= 4) + addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; + I915_WRITE(HWS_PGA, addr); + + ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; + memset(ring->status_page.page_addr, 0, PAGE_SIZE); + + return 0; +} + static int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -1086,6 +1098,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); ring->size = 32 * PAGE_SIZE; + memset(ring->sync_seqno, 0, sizeof(ring->sync_seqno)); init_waitqueue_head(&ring->irq_queue); @@ -1093,6 +1106,11 @@ static int intel_init_ring_buffer(struct drm_device *dev, ret = init_status_page(ring); if (ret) return ret; + } else { + BUG_ON(ring->id != RCS); + ret = init_phys_hws_pga(ring); + if (ret) + return ret; } obj = i915_gem_alloc_object(dev, ring->size); @@ -1157,7 +1175,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) /* Disable the ring buffer. The ring must be idle at this point */ dev_priv = ring->dev->dev_private; - ret = intel_wait_ring_idle(ring); + ret = intel_ring_idle(ring); if (ret) DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", ring->name, ret); @@ -1176,28 +1194,6 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) cleanup_status_page(ring); } -static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) -{ - uint32_t __iomem *virt; - int rem = ring->size - ring->tail; - - if (ring->space < rem) { - int ret = intel_wait_ring_buffer(ring, rem); - if (ret) - return ret; - } - - virt = ring->virtual_start + ring->tail; - rem /= 4; - while (rem--) - iowrite32(MI_NOOP, virt++); - - ring->tail = 0; - ring->space = ring_space(ring); - - return 0; -} - static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno) { int ret; @@ -1231,7 +1227,7 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) if (request->tail == -1) continue; - space = request->tail - (ring->tail + 8); + space = request->tail - (ring->tail + I915_RING_FREE_SPACE); if (space < 0) space += ring->size; if (space >= n) { @@ -1266,7 +1262,7 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) return 0; } -int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) +static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1309,6 +1305,60 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) return -EBUSY; } +static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) +{ + uint32_t __iomem *virt; + int rem = ring->size - ring->tail; + + if (ring->space < rem) { + int ret = ring_wait_for_space(ring, rem); + if (ret) + return ret; + } + + virt = ring->virtual_start + ring->tail; + rem /= 4; + while (rem--) + iowrite32(MI_NOOP, virt++); + + ring->tail = 0; + ring->space = ring_space(ring); + + return 0; +} + +int intel_ring_idle(struct intel_ring_buffer *ring) +{ + u32 seqno; + int ret; + + /* We need to add any requests required to flush the objects and ring */ + if (ring->outstanding_lazy_request) { + ret = i915_add_request(ring, NULL, NULL); + if (ret) + return ret; + } + + /* Wait upon the last request to be completed */ + if (list_empty(&ring->request_list)) + return 0; + + seqno = list_entry(ring->request_list.prev, + struct drm_i915_gem_request, + list)->seqno; + + return i915_wait_seqno(ring, seqno); +} + +static int +intel_ring_alloc_seqno(struct intel_ring_buffer *ring) +{ + if (ring->outstanding_lazy_request) + return 0; + + return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_request); +} + int intel_ring_begin(struct intel_ring_buffer *ring, int num_dwords) { @@ -1320,6 +1370,11 @@ int intel_ring_begin(struct intel_ring_buffer *ring, if (ret) return ret; + /* Preallocate the olr before touching the ring */ + ret = intel_ring_alloc_seqno(ring); + if (ret) + return ret; + if (unlikely(ring->tail + n > ring->effective_size)) { ret = intel_wrap_ring_buffer(ring); if (unlikely(ret)) @@ -1327,7 +1382,7 @@ int intel_ring_begin(struct intel_ring_buffer *ring, } if (unlikely(ring->space < n)) { - ret = intel_wait_ring_buffer(ring, n); + ret = ring_wait_for_space(ring, n); if (unlikely(ret)) return ret; } @@ -1391,10 +1446,17 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, return ret; cmd = MI_FLUSH_DW; + /* + * Bspec vol 1c.5 - video engine command streamer: + * "If ENABLED, all TLBs will be invalidated once the flush + * operation is complete. This bit is only valid when the + * Post-Sync Operation field is a value of 1h or 3h." + */ if (invalidate & I915_GEM_GPU_DOMAINS) - cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD; + cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD | + MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW; intel_ring_emit(ring, cmd); - intel_ring_emit(ring, 0); + intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT); intel_ring_emit(ring, 0); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); @@ -1402,8 +1464,30 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, } static int +hsw_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, + u32 offset, u32 len, + unsigned flags) +{ + int ret; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, + MI_BATCH_BUFFER_START | MI_BATCH_PPGTT_HSW | + (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_HSW)); + /* bit0-7 is the length on GEN6+ */ + intel_ring_emit(ring, offset); + intel_ring_advance(ring); + + return 0; +} + +static int gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - u32 offset, u32 len) + u32 offset, u32 len, + unsigned flags) { int ret; @@ -1411,7 +1495,9 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, if (ret) return ret; - intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); + intel_ring_emit(ring, + MI_BATCH_BUFFER_START | + (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE_I965)); /* bit0-7 is the length on GEN6+ */ intel_ring_emit(ring, offset); intel_ring_advance(ring); @@ -1432,10 +1518,17 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, return ret; cmd = MI_FLUSH_DW; + /* + * Bspec vol 1c.3 - blitter engine command streamer: + * "If ENABLED, all TLBs will be invalidated once the flush + * operation is complete. This bit is only valid when the + * Post-Sync Operation field is a value of 1h or 3h." + */ if (invalidate & I915_GEM_DOMAIN_RENDER) - cmd |= MI_INVALIDATE_TLB; + cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX | + MI_FLUSH_DW_OP_STOREDW; intel_ring_emit(ring, cmd); - intel_ring_emit(ring, 0); + intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT); intel_ring_emit(ring, 0); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); @@ -1490,7 +1583,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_enable_mask = I915_USER_INTERRUPT; } ring->write_tail = ring_write_tail; - if (INTEL_INFO(dev)->gen >= 6) + if (IS_HASWELL(dev)) + ring->dispatch_execbuffer = hsw_ring_dispatch_execbuffer; + else if (INTEL_INFO(dev)->gen >= 6) ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; else if (INTEL_INFO(dev)->gen >= 4) ring->dispatch_execbuffer = i965_dispatch_execbuffer; @@ -1501,12 +1596,6 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->init = init_render_ring; ring->cleanup = render_ring_cleanup; - - if (!I915_NEED_GFX_HWS(dev)) { - ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; - memset(ring->status_page.page_addr, 0, PAGE_SIZE); - } - return intel_init_ring_buffer(dev, ring); } @@ -1514,6 +1603,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + int ret; ring->name = "render ring"; ring->id = RCS; @@ -1551,16 +1641,13 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->init = init_render_ring; ring->cleanup = render_ring_cleanup; - if (!I915_NEED_GFX_HWS(dev)) - ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; - ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); ring->size = size; ring->effective_size = ring->size; - if (IS_I830(ring->dev)) + if (IS_I830(ring->dev) || IS_845G(ring->dev)) ring->effective_size -= 128; ring->virtual_start = ioremap_wc(start, size); @@ -1570,6 +1657,12 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) return -ENOMEM; } + if (!I915_NEED_GFX_HWS(dev)) { + ret = init_phys_hws_pga(ring); + if (ret) + return ret; + } + return 0; } @@ -1618,7 +1711,6 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) } ring->init = init_ring_common; - return intel_init_ring_buffer(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2ea7a31..526182e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -1,6 +1,17 @@ #ifndef _INTEL_RINGBUFFER_H_ #define _INTEL_RINGBUFFER_H_ +/* + * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use" + * Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use" + * Gen4+ BSpec "vol1c Memory Interface and Command Stream" / 5.3.4.5 "Ring Buffer Use" + * + * "If the Ring Buffer Head Pointer and the Tail Pointer are on the same + * cacheline, the Head Pointer must not be greater than the Tail + * Pointer." + */ +#define I915_RING_FREE_SPACE 64 + struct intel_hw_status_page { u32 *page_addr; unsigned int gfx_addr; @@ -70,8 +81,7 @@ struct intel_ring_buffer { int __must_check (*flush)(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains); - int (*add_request)(struct intel_ring_buffer *ring, - u32 *seqno); + int (*add_request)(struct intel_ring_buffer *ring); /* Some chipsets are not quite as coherent as advertised and need * an expensive kick to force a true read of the up-to-date seqno. * However, the up-to-date seqno is not always required and the last @@ -81,7 +91,9 @@ struct intel_ring_buffer { u32 (*get_seqno)(struct intel_ring_buffer *ring, bool lazy_coherency); int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, - u32 offset, u32 length); + u32 offset, u32 length, + unsigned flags); +#define I915_DISPATCH_SECURE 0x1 void (*cleanup)(struct intel_ring_buffer *ring); int (*sync_to)(struct intel_ring_buffer *ring, struct intel_ring_buffer *to, @@ -181,27 +193,21 @@ intel_read_status_page(struct intel_ring_buffer *ring, * The area from dword 0x20 to 0x3ff is available for driver usage. */ #define I915_GEM_HWS_INDEX 0x20 +#define I915_GEM_HWS_SCRATCH_INDEX 0x30 +#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT) void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); -int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); -static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring) -{ - return intel_wait_ring_buffer(ring, ring->size - 8); -} - int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); - static inline void intel_ring_emit(struct intel_ring_buffer *ring, u32 data) { iowrite32(data, ring->virtual_start + ring->tail); ring->tail += 4; } - void intel_ring_advance(struct intel_ring_buffer *ring); +int __must_check intel_ring_idle(struct intel_ring_buffer *ring); -u32 intel_ring_get_seqno(struct intel_ring_buffer *ring); int intel_ring_flush_all_caches(struct intel_ring_buffer *ring); int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); @@ -217,6 +223,12 @@ static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring) return ring->tail; } +static inline u32 intel_ring_get_seqno(struct intel_ring_buffer *ring) +{ + BUG_ON(ring->outstanding_lazy_request == 0); + return ring->outstanding_lazy_request; +} + static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno) { if (ring->trace_irq_seqno == 0 && ring->irq_get(ring)) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a6ac0b4..c275bf0 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -509,7 +509,7 @@ out: static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, int response_len) { - u8 retry = 5; + u8 retry = 15; /* 5 quick checks, followed by 10 long checks */ u8 status; int i; @@ -522,14 +522,27 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, * command to be complete. * * Check 5 times in case the hardware failed to read the docs. + * + * Also beware that the first response by many devices is to + * reply PENDING and stall for time. TVs are notorious for + * requiring longer than specified to complete their replies. + * Originally (in the DDX long ago), the delay was only ever 15ms + * with an additional delay of 30ms applied for TVs added later after + * many experiments. To accommodate both sets of delays, we do a + * sequence of slow checks if the device is falling behind and fails + * to reply within 5*15µs. */ if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, &status)) goto log_fail; - while (status == SDVO_CMD_STATUS_PENDING && retry--) { - udelay(15); + while (status == SDVO_CMD_STATUS_PENDING && --retry) { + if (retry < 10) + msleep(15); + else + udelay(15); + if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, &status)) @@ -1228,6 +1241,30 @@ static void intel_disable_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(encoder->base.dev)) { + struct drm_crtc *crtc = encoder->base.crtc; + int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; + + if (temp & SDVO_PIPE_B_SELECT) { + temp &= ~SDVO_PIPE_B_SELECT; + I915_WRITE(intel_sdvo->sdvo_reg, temp); + POSTING_READ(intel_sdvo->sdvo_reg); + + /* Again we need to write this twice. */ + I915_WRITE(intel_sdvo->sdvo_reg, temp); + POSTING_READ(intel_sdvo->sdvo_reg); + + /* Transcoder selection bits only update + * effectively on vblank. */ + if (crtc) + intel_wait_for_vblank(encoder->base.dev, pipe); + else + msleep(50); + } + } + intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE); } } @@ -1244,8 +1281,20 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) u8 status; temp = I915_READ(intel_sdvo->sdvo_reg); - if ((temp & SDVO_ENABLE) == 0) + 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; + } + intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); + } for (i = 0; i < 2; i++) intel_wait_for_vblank(dev, intel_crtc->pipe); @@ -1499,15 +1548,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status ret; - if (!intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) - return connector_status_unknown; - - /* add 30ms delay when the output type might be TV */ - if (intel_sdvo->caps.output_flags & SDVO_TV_MASK) - msleep(30); - - if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_ATTACHED_DISPLAYS, + &response, 2)) return connector_status_unknown; DRM_DEBUG_KMS("SDVO response %d %d [%x]\n", @@ -1796,7 +1839,7 @@ static void intel_sdvo_destroy(struct drm_connector *connector) intel_sdvo_destroy_enhance_property(connector); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); - kfree(connector); + kfree(intel_sdvo_connector); } static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) @@ -1828,7 +1871,7 @@ intel_sdvo_set_property(struct drm_connector *connector, uint8_t cmd; int ret; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; @@ -1883,7 +1926,7 @@ intel_sdvo_set_property(struct drm_connector *connector, } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { temp_value = val; if (intel_sdvo_connector->left == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->right, val); if (intel_sdvo_connector->left_margin == temp_value) return 0; @@ -1895,7 +1938,7 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_H; goto set_value; } else if (intel_sdvo_connector->right == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->left, val); if (intel_sdvo_connector->right_margin == temp_value) return 0; @@ -1907,7 +1950,7 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_H; goto set_value; } else if (intel_sdvo_connector->top == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->bottom, val); if (intel_sdvo_connector->top_margin == temp_value) return 0; @@ -1919,7 +1962,7 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_V; goto set_value; } else if (intel_sdvo_connector->bottom == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->top, val); if (intel_sdvo_connector->bottom_margin == temp_value) return 0; @@ -2072,17 +2115,24 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, else mapping = &dev_priv->sdvo_mappings[1]; - pin = GMBUS_PORT_DPB; - if (mapping->initialized) + if (mapping->initialized && intel_gmbus_is_port_valid(mapping->i2c_pin)) pin = mapping->i2c_pin; + else + pin = GMBUS_PORT_DPB; - if (intel_gmbus_is_port_valid(pin)) { - sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); - intel_gmbus_set_speed(sdvo->i2c, GMBUS_RATE_1MHZ); - intel_gmbus_force_bit(sdvo->i2c, true); - } else { - sdvo->i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); - } + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); + + /* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow + * our code totally fails once we start using gmbus. Hence fall back to + * bit banging for now. */ + intel_gmbus_force_bit(sdvo->i2c, true); +} + +/* undo any changes intel_sdvo_select_i2c_bus() did to sdvo->i2c */ +static void +intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo) +{ + intel_gmbus_force_bit(sdvo->i2c, false); } static bool @@ -2427,7 +2477,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; - drm_connector_attach_property(&intel_sdvo_connector->base.base, + drm_object_attach_property(&intel_sdvo_connector->base.base.base, intel_sdvo_connector->tv_format, 0); return true; @@ -2443,7 +2493,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->name = \ drm_property_create_range(dev, 0, #name, 0, data_value[0]); \ if (!intel_sdvo_connector->name) return false; \ - drm_connector_attach_property(connector, \ + drm_object_attach_property(&connector->base, \ intel_sdvo_connector->name, \ intel_sdvo_connector->cur_##name); \ DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ @@ -2480,7 +2530,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->left) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->left, intel_sdvo_connector->left_margin); @@ -2489,7 +2539,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->right) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->right, intel_sdvo_connector->right_margin); DRM_DEBUG_KMS("h_overscan: max %d, " @@ -2517,7 +2567,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->top) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->top, intel_sdvo_connector->top_margin); @@ -2527,7 +2577,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->bottom) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->bottom, intel_sdvo_connector->bottom_margin); DRM_DEBUG_KMS("v_overscan: max %d, " @@ -2559,7 +2609,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->dot_crawl) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->dot_crawl, intel_sdvo_connector->cur_dot_crawl); DRM_DEBUG_KMS("dot crawl: current %d\n", response); @@ -2663,10 +2713,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) intel_sdvo->is_sdvob = is_sdvob; intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1; intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg); - if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) { - kfree(intel_sdvo); - return false; - } + if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) + goto err_i2c_bus; /* encoder type will be decided later */ intel_encoder = &intel_sdvo->base; @@ -2765,6 +2813,8 @@ err_output: err: drm_encoder_cleanup(&intel_encoder->base); i2c_del_adapter(&intel_sdvo->ddc); +err_i2c_bus: + intel_sdvo_unselect_i2c_bus(intel_sdvo); kfree(intel_sdvo); return false; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 82f5e5c7..827dcd4 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -48,7 +48,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; u32 sprctl, sprscale = 0; - int pixel_size; + unsigned long sprsurf_offset, linear_offset; + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); sprctl = I915_READ(SPRCTL(pipe)); @@ -61,33 +62,24 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; - pixel_size = 4; break; case DRM_FORMAT_XRGB8888: sprctl |= SPRITE_FORMAT_RGBX888; - pixel_size = 4; break; case DRM_FORMAT_YUYV: sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV; - pixel_size = 2; break; case DRM_FORMAT_YVYU: sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU; - pixel_size = 2; break; case DRM_FORMAT_UYVY: sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY; - pixel_size = 2; break; case DRM_FORMAT_VYUY: sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY; - pixel_size = 2; break; default: - DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); - sprctl |= SPRITE_FORMAT_RGBX888; - pixel_size = 4; - break; + BUG(); } if (obj->tiling_mode != I915_TILING_NONE) @@ -127,18 +119,28 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); - if (obj->tiling_mode != I915_TILING_NONE) { + + linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + sprsurf_offset = + intel_gen4_compute_offset_xtiled(&x, &y, + fb->bits_per_pixel / 8, + fb->pitches[0]); + linear_offset -= sprsurf_offset; + + /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET + * register */ + if (IS_HASWELL(dev)) + I915_WRITE(SPROFFSET(pipe), (y << 16) | x); + else if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x); - } else { - unsigned long offset; + else + I915_WRITE(SPRLINOFF(pipe), linear_offset); - offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); - I915_WRITE(SPRLINOFF(pipe), offset); - } I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); - I915_WRITE(SPRSCALE(pipe), sprscale); + if (intel_plane->can_scale) + I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); - I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset); + I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); } @@ -152,7 +154,8 @@ ivb_disable_plane(struct drm_plane *plane) I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ - I915_WRITE(SPRSCALE(pipe), 0); + if (intel_plane->can_scale) + I915_WRITE(SPRSCALE(pipe), 0); /* Activate double buffered register update */ I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); @@ -225,8 +228,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); - int pipe = intel_plane->pipe, pixel_size; + int pipe = intel_plane->pipe; + unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); dvscntr = I915_READ(DVSCNTR(pipe)); @@ -239,33 +244,24 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR; - pixel_size = 4; break; case DRM_FORMAT_XRGB8888: dvscntr |= DVS_FORMAT_RGBX888; - pixel_size = 4; break; case DRM_FORMAT_YUYV: dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV; - pixel_size = 2; break; case DRM_FORMAT_YVYU: dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU; - pixel_size = 2; break; case DRM_FORMAT_UYVY: dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY; - pixel_size = 2; break; case DRM_FORMAT_VYUY: dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY; - pixel_size = 2; break; default: - DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n"); - dvscntr |= DVS_FORMAT_RGBX888; - pixel_size = 4; - break; + BUG(); } if (obj->tiling_mode != I915_TILING_NONE) @@ -289,18 +285,23 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); - if (obj->tiling_mode != I915_TILING_NONE) { + + linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); + dvssurf_offset = + intel_gen4_compute_offset_xtiled(&x, &y, + fb->bits_per_pixel / 8, + fb->pitches[0]); + linear_offset -= dvssurf_offset; + + if (obj->tiling_mode != I915_TILING_NONE) I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x); - } else { - unsigned long offset; + else + I915_WRITE(DVSLINOFF(pipe), linear_offset); - offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); - I915_WRITE(DVSLINOFF(pipe), offset); - } I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); - I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset); + I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset); POSTING_READ(DVSSURF(pipe)); } @@ -422,6 +423,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj, *old_obj; int pipe = intel_plane->pipe; + enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, + pipe); int ret = 0; int x = src_x >> 16, y = src_y >> 16; int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; @@ -436,7 +439,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, src_h = src_h >> 16; /* Pipe must be running... */ - if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) + if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) return -EINVAL; if (crtc_x >= primary_w || crtc_y >= primary_h) @@ -446,6 +449,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (intel_plane->pipe != intel_crtc->pipe) return -EINVAL; + /* Sprite planes can be linear or x-tiled surfaces */ + switch (obj->tiling_mode) { + case I915_TILING_NONE: + case I915_TILING_X: + break; + default: + return -EINVAL; + } + /* * Clamp the width & height into the visible area. Note we don't * try to scale the source if part of the visible region is offscreen. @@ -473,6 +485,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, goto out; /* + * We may not have a scaler, eg. HSW does not have it any more + */ + if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h)) + return -EINVAL; + + /* * We can take a larger source and scale it down, but * only so much... 16x is the max on SNB. */ @@ -665,6 +683,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) switch (INTEL_INFO(dev)->gen) { case 5: case 6: + intel_plane->can_scale = true; intel_plane->max_downscale = 16; intel_plane->update_plane = ilk_update_plane; intel_plane->disable_plane = ilk_disable_plane; @@ -681,6 +700,10 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) break; case 7: + if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev)) + 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; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 62bb048..ea93520 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1088,13 +1088,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, int dspcntr_reg = DSPCNTR(intel_crtc->plane); int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); - int dspbase_reg = DSPADDR(intel_crtc->plane); int xpos = 0x0, ypos = 0x0; unsigned int xsize, ysize; /* Pipe must be off here */ I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + intel_flush_display_plane(dev_priv, intel_crtc->plane); /* Wait for vblank for the disable to take effect */ if (IS_GEN2(dev)) @@ -1123,8 +1121,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, I915_WRITE(pipeconf_reg, pipeconf); I915_WRITE(dspcntr_reg, dspcntr); - /* Flush the plane changes */ - I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + intel_flush_display_plane(dev_priv, intel_crtc->plane); } j = 0; @@ -1292,7 +1289,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) } intel_tv->tv_format = tv_mode->name; - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, connector->dev->mode_config.tv_mode_property, i); } @@ -1446,7 +1443,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop int ret = 0; bool changed = false; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret < 0) goto out; @@ -1658,18 +1655,18 @@ intel_tv_init(struct drm_device *dev) ARRAY_SIZE(tv_modes), tv_format_names); - drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, + drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property, initial_mode); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_left_margin_property, intel_tv->margin[TV_MARGIN_LEFT]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_top_margin_property, intel_tv->margin[TV_MARGIN_TOP]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_right_margin_property, intel_tv->margin[TV_MARGIN_RIGHT]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_bottom_margin_property, intel_tv->margin[TV_MARGIN_BOTTOM]); drm_sysfs_connector_add(connector); |