diff options
author | Dave Airlie <airlied@redhat.com> | 2015-01-27 09:01:09 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-01-27 09:01:09 +1000 |
commit | d3e7a0dabd6f5c5f45fbde9ed48a18f09ea97dce (patch) | |
tree | 7b8bcadd184034fc407c723f23147fe663bf819f /drivers | |
parent | e4514003c6d0afd0a2d7e23e397530d746f34057 (diff) | |
parent | 0a0c0018f6badd4adebe1cb453dc42143a464f87 (diff) |
Merge tag 'drm-intel-next-2015-01-17' of git://anongit.freedesktop.org/drm-intel into drm-next
- refactor i915/snd-hda interaction to use the component framework (Imre)
- psr cleanups and small fixes (Rodrigo)
- a few perf w/a from Ken Graunke
- switch to atomic plane helpers (Matt Roper)
- wc mmap support (Chris Wilson & Akash Goel)
- smaller things all over
* tag 'drm-intel-next-2015-01-17' of git://anongit.freedesktop.org/drm-intel: (40 commits)
drm/i915: Update DRIVER_DATE to 20150117
i915: reuse %ph to dump small buffers
drm/i915: Ensure the HiZ RAW Stall Optimization is on for Cherryview.
drm/i915: Enable the HiZ RAW Stall Optimization on Broadwell.
drm/i915: PSR link standby at debugfs
drm/i915: group link_standby setup and let this info visible everywhere.
drm/i915: Add missing vbt check.
drm/i915: PSR HSW/BDW: Fix inverted logic at sink main_link_active bit.
drm/i915: PSR VLV/CHV: Remove condition checks that only applies to Haswell.
drm/i915: VLV/CHV PSR needs to exit PSR on every flush.
drm/i915: Fix kerneldoc for i915 atomic plane code
drm/i915: Don't pretend SDVO hotplug works on 915
drm/i915: Don't register HDMI connectors for eDP ports on VLV/CHV
drm/i915: Remove I915_HAS_HOTPLUG() check from i915_hpd_irq_setup()
drm/i915: Make hpd arrays big enough to avoid out of bounds access
Revert "drm/i915/chv: Use timeout mode for RC6 on chv"
drm/i915: Improve HiZ throughput on Cherryview.
drm/i915: Reset CSB read pointer in ring init
drm/i915: Drop unused position fields (v2)
drm/i915: Move to atomic plane helpers (v9)
...
Diffstat (limited to 'drivers')
25 files changed, 840 insertions, 521 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 1849ffae61ae..16e3dc350274 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -66,6 +66,7 @@ i915-y += dvo_ch7017.o \ dvo_ns2501.o \ dvo_sil164.o \ dvo_tfp410.o \ + intel_atomic_plane.o \ intel_crt.o \ intel_ddi.o \ intel_dp.o \ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e515aad47858..0d11cbe9f80c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2248,6 +2248,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) } seq_puts(m, "\n"); + seq_printf(m, "Link standby: %s\n", + yesno((bool)dev_priv->psr.link_standby)); + /* CHV PSR has no kind of performance counter */ if (HAS_PSR(dev) && HAS_DDI(dev)) { psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) & diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 52730ed86385..2447de36de44 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -143,6 +143,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_COHERENT_PHYS_GTT: value = 1; break; + case I915_PARAM_MMAP_VERSION: + value = 1; + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; @@ -830,6 +833,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_runtime_pm_enable(dev_priv); + i915_audio_component_init(dev_priv); + return 0; out_power_well: @@ -870,6 +875,8 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + i915_audio_component_cleanup(dev_priv); + ret = i915_gem_suspend(dev); if (ret) { DRM_ERROR("failed to idle hardware: %d\n", ret); @@ -1063,6 +1070,8 @@ const struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int i915_max_ioctl = ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0763fa0791e3..308774f42079 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -942,8 +942,7 @@ static int i915_pm_suspend(struct device *dev) static int i915_pm_suspend_late(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; /* * We have a suspedn ordering issue with the snd-hda driver also @@ -962,8 +961,7 @@ static int i915_pm_suspend_late(struct device *dev) static int i915_pm_resume_early(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -973,8 +971,7 @@ static int i915_pm_resume_early(struct device *dev) static int i915_pm_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 54f2a275dba6..ede48628bf85 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -55,7 +55,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20141219" +#define DRIVER_DATE "20150117" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ @@ -83,7 +83,7 @@ int __ret_warn_on = !!(condition); \ if (unlikely(__ret_warn_on)) { \ if (i915.verbose_state_checks) \ - __WARN_printf(format); \ + WARN(1, format); \ else \ DRM_ERROR(format); \ } \ @@ -94,7 +94,7 @@ int __ret_warn_on = !!(condition); \ if (unlikely(__ret_warn_on)) { \ if (i915.verbose_state_checks) \ - __WARN_printf("WARN_ON(" #condition ")\n"); \ + WARN(1, "WARN_ON(" #condition ")\n"); \ else \ DRM_ERROR("WARN_ON(" #condition ")\n"); \ } \ @@ -678,6 +678,11 @@ struct i915_ctx_hang_stats { /* Time when this context was last blamed for a GPU reset */ unsigned long guilty_ts; + /* If the contexts causes a second GPU hang within this time, + * it is permanently banned from submitting any more work. + */ + unsigned long ban_period_seconds; + /* This context is banned to submit more work */ bool banned; }; @@ -784,6 +789,7 @@ struct i915_psr { bool active; struct delayed_work work; unsigned busy_frontbuffer_bits; + bool link_standby; }; enum intel_pch { @@ -1409,7 +1415,6 @@ struct intel_vbt_data { bool present; bool active_low_pwm; u8 min_brightness; /* min_brightness/255 of max */ - u8 controller; /* brightness controller number */ } backlight; /* MIPI DSI */ @@ -1768,6 +1773,9 @@ struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; + /* hda/i915 audio component */ + bool audio_component_registered; + uint32_t hw_context_size; struct list_head context_list; @@ -1853,6 +1861,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev) return dev->dev_private; } +static inline struct drm_i915_private *dev_to_i915(struct device *dev) +{ + return to_i915(dev_get_drvdata(dev)); +} + /* Iterate over initialised rings */ #define for_each_ring(ring__, dev_priv__, i__) \ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ @@ -2892,6 +2905,10 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* i915_gem_evict.c */ int __must_check i915_gem_evict_something(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4e4d969d3b28..6c403654e33a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -153,12 +153,6 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) return 0; } -static inline bool -i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) -{ - return i915_gem_obj_bound_any(obj) && !obj->active; -} - int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file) @@ -1487,18 +1481,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, if (ret) goto unref; - if (read_domains & I915_GEM_DOMAIN_GTT) { + if (read_domains & I915_GEM_DOMAIN_GTT) ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); - - /* Silently promote "you're not bound, there was nothing to do" - * to success, since the client was just asking us to - * make sure everything was done. - */ - if (ret == -EINVAL) - ret = 0; - } else { + else ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); - } unref: drm_gem_object_unreference(&obj->base); @@ -1563,6 +1549,12 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; unsigned long addr; + if (args->flags & ~(I915_MMAP_WC)) + return -EINVAL; + + if (args->flags & I915_MMAP_WC && !cpu_has_pat) + return -ENODEV; + obj = drm_gem_object_lookup(dev, file, args->handle); if (obj == NULL) return -ENOENT; @@ -1578,6 +1570,19 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, addr = vm_mmap(obj->filp, 0, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, args->offset); + if (args->flags & I915_MMAP_WC) { + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + + down_write(&mm->mmap_sem); + vma = find_vma(mm, addr); + if (vma) + vma->vm_page_prot = + pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + else + addr = -ENOMEM; + up_write(&mm->mmap_sem); + } drm_gem_object_unreference_unlocked(obj); if (IS_ERR((void *)addr)) return addr; @@ -2529,7 +2534,8 @@ static bool i915_context_is_banned(struct drm_i915_private *dev_priv, if (ctx->hang_stats.banned) return true; - if (elapsed <= DRM_I915_CTX_BAN_PERIOD) { + if (ctx->hang_stats.ban_period_seconds && + elapsed <= ctx->hang_stats.ban_period_seconds) { if (!i915_gem_context_is_default(ctx)) { DRM_DEBUG("context hanging too fast, banning!\n"); return true; @@ -3698,15 +3704,10 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj, int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct i915_vma *vma = i915_gem_obj_to_ggtt(obj); uint32_t old_write_domain, old_read_domains; + struct i915_vma *vma; int ret; - /* Not valid to be called on unbound objects. */ - if (vma == NULL) - return -EINVAL; - if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) return 0; @@ -3715,6 +3716,19 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) return ret; i915_gem_object_retire(obj); + + /* Flush and acquire obj->pages so that we are coherent through + * direct access in memory with previous cached writes through + * shmemfs and that our cache domain tracking remains valid. + * For example, if the obj->filp was moved to swap without us + * being notified and releasing the pages, we would mistakenly + * continue to assume that the obj remained out of the CPU cached + * domain. + */ + ret = i915_gem_object_get_pages(obj); + if (ret) + return ret; + i915_gem_object_flush_cpu_write_domain(obj, false); /* Serialise direct access to this object with the barriers for @@ -3746,9 +3760,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) old_write_domain); /* And bump the LRU for this access */ - if (i915_gem_object_is_inactive(obj)) + vma = i915_gem_obj_to_ggtt(obj); + if (vma && drm_mm_node_allocated(&vma->node) && !obj->active) list_move_tail(&vma->mm_list, - &dev_priv->gtt.base.inactive_list); + &to_i915(obj->base.dev)->gtt.base.inactive_list); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 9b23fb1f5bf6..8603bf48d3ee 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -222,6 +222,8 @@ __create_hw_context(struct drm_device *dev, * is no remap info, it will be a NOP. */ ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1; + ctx->hang_stats.ban_period_seconds = DRM_I915_CTX_BAN_PERIOD; + return ctx; err_out: @@ -792,3 +794,72 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id); return 0; } + +int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + struct drm_i915_gem_context_param *args = data; + struct intel_context *ctx; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + ctx = i915_gem_context_get(file_priv, args->ctx_id); + if (IS_ERR(ctx)) { + mutex_unlock(&dev->struct_mutex); + return PTR_ERR(ctx); + } + + args->size = 0; + switch (args->param) { + case I915_CONTEXT_PARAM_BAN_PERIOD: + args->value = ctx->hang_stats.ban_period_seconds; + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_file_private *file_priv = file->driver_priv; + struct drm_i915_gem_context_param *args = data; + struct intel_context *ctx; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + ctx = i915_gem_context_get(file_priv, args->ctx_id); + if (IS_ERR(ctx)) { + mutex_unlock(&dev->struct_mutex); + return PTR_ERR(ctx); + } + + switch (args->param) { + case I915_CONTEXT_PARAM_BAN_PERIOD: + if (args->size) + ret = -EINVAL; + else if (args->value < ctx->hang_stats.ban_period_seconds && + !capable(CAP_SYS_ADMIN)) + ret = -EPERM; + else + ctx->hang_stats.ban_period_seconds = args->value; + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&dev->struct_mutex); + + return ret; +} diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 886ff2ee7a28..e3a49d94da3a 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -50,11 +50,12 @@ mark_free(struct i915_vma *vma, struct list_head *unwind) * i915_gem_evict_something - Evict vmas to make room for binding a new one * @dev: drm_device * @vm: address space to evict from - * @size: size of the desired free space + * @min_size: size of the desired free space * @alignment: alignment constraint of the desired free space * @cache_level: cache_level for the desired space - * @mappable: whether the free space must be mappable - * @nonblocking: whether evicting active objects is allowed or not + * @start: start (inclusive) of the range from which to evict objects + * @end: end (exclusive) of the range from which to evict objects + * @flags: additional flags to control the eviction algorithm * * This function will try to evict vmas until a free space satisfying the * requirements is found. Callers must check first whether any such hole exists @@ -196,7 +197,6 @@ found: /** * i915_gem_evict_vm - Evict all idle vmas from a vm - * * @vm: Address space to cleanse * @do_idle: Boolean directing whether to idle first. * @@ -214,6 +214,7 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) struct i915_vma *vma, *next; int ret; + WARN_ON(!mutex_is_locked(&vm->dev->struct_mutex)); trace_i915_gem_evict_vm(vm); if (do_idle) { @@ -222,6 +223,8 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) return ret; i915_gem_retire_requests(vm->dev); + + WARN_ON(!list_empty(&vm->active_list)); } list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1d6e0929ab83..e3ef17783765 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1081,6 +1081,7 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring, { struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev); struct drm_i915_gem_object *shadow_batch_obj; + bool need_reloc = false; int ret; shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool, @@ -1106,6 +1107,7 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring, vma->exec_entry = shadow_exec_entry; vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE; drm_gem_object_reference(&shadow_batch_obj->base); + i915_gem_execbuffer_reserve_vma(vma, ring, &need_reloc); list_add_tail(&vma->exec_list, &eb->vmas); shadow_batch_obj->base.pending_read_domains = diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 818ab4e9dabc..8fe5a87705f7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -45,7 +45,7 @@ * and related files, but that will be described in separate chapters. */ -static const u32 hpd_ibx[] = { +static const u32 hpd_ibx[HPD_NUM_PINS] = { [HPD_CRT] = SDE_CRT_HOTPLUG, [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, [HPD_PORT_B] = SDE_PORTB_HOTPLUG, @@ -53,7 +53,7 @@ static const u32 hpd_ibx[] = { [HPD_PORT_D] = SDE_PORTD_HOTPLUG }; -static const u32 hpd_cpt[] = { +static const u32 hpd_cpt[HPD_NUM_PINS] = { [HPD_CRT] = SDE_CRT_HOTPLUG_CPT, [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT, [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, @@ -61,7 +61,7 @@ static const u32 hpd_cpt[] = { [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT }; -static const u32 hpd_mask_i915[] = { +static const u32 hpd_mask_i915[HPD_NUM_PINS] = { [HPD_CRT] = CRT_HOTPLUG_INT_EN, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, @@ -70,7 +70,7 @@ static const u32 hpd_mask_i915[] = { [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN }; -static const u32 hpd_status_g4x[] = { +static const u32 hpd_status_g4x[HPD_NUM_PINS] = { [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, @@ -79,7 +79,7 @@ static const u32 hpd_status_g4x[] = { [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; -static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ +static const u32 hpd_status_i915[HPD_NUM_PINS] = { /* i915 and valleyview are the same */ [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, @@ -1522,7 +1522,7 @@ static inline enum port get_port_from_pin(enum hpd_pin pin) static inline void intel_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger, u32 dig_hotplug_reg, - const u32 *hpd) + const u32 hpd[HPD_NUM_PINS]) { struct drm_i915_private *dev_priv = dev->dev_private; int i; @@ -4145,26 +4145,24 @@ static void i915_hpd_irq_setup(struct drm_device *dev) assert_spin_locked(&dev_priv->irq_lock); - if (I915_HAS_HOTPLUG(dev)) { - hotplug_en = I915_READ(PORT_HOTPLUG_EN); - hotplug_en &= ~HOTPLUG_INT_EN_MASK; - /* Note HDMI and DP share hotplug bits */ - /* enable bits are the same for all generations */ - for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) - hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; - /* Programming the CRT detection parameters tends - to generate a spurious hotplug event about three - seconds later. So just do it once. - */ - if (IS_G4X(dev)) - hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; - hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK; - hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; - - /* Ignore TV since it's buggy */ - I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - } + hotplug_en = I915_READ(PORT_HOTPLUG_EN); + hotplug_en &= ~HOTPLUG_INT_EN_MASK; + /* Note HDMI and DP share hotplug bits */ + /* enable bits are the same for all generations */ + for_each_intel_encoder(dev, intel_encoder) + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; + /* Programming the CRT detection parameters tends + to generate a spurious hotplug event about three + seconds later. So just do it once. + */ + if (IS_G4X(dev)) + hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; + hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK; + hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + + /* Ignore TV since it's buggy */ + I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); } static irqreturn_t i965_irq_handler(int irq, void *arg) @@ -4428,14 +4426,14 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev->driver->irq_postinstall = i915_irq_postinstall; dev->driver->irq_uninstall = i915_irq_uninstall; dev->driver->irq_handler = i915_irq_handler; - dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else { dev->driver->irq_preinstall = i965_irq_preinstall; dev->driver->irq_postinstall = i965_irq_postinstall; dev->driver->irq_uninstall = i965_irq_uninstall; dev->driver->irq_handler = i965_irq_handler; - dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } + if (I915_HAS_HOTPLUG(dev_priv)) + dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; dev->driver->enable_vblank = i915_enable_vblank; dev->driver->disable_vblank = i915_disable_vblank; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 40ca873a05ad..a39bb0385bcb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5202,6 +5202,9 @@ enum punit_power_well { #define COMMON_SLICE_CHICKEN2 0x7014 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0) +#define HIZ_CHICKEN 0x7018 +# define CHV_HZ_8X8_MODE_IN_1X (1<<15) + #define GEN7_L3SQCREG1 0xB010 #define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 @@ -6167,6 +6170,7 @@ enum punit_power_well { #define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) #define HALF_SLICE_CHICKEN3 0xe184 +#define HSW_SAMPLE_C_PERFORMANCE (1<<9) #define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8) #define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c new file mode 100644 index 000000000000..5488efef1837 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -0,0 +1,152 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * DOC: atomic plane helpers + * + * The functions here are used by the atomic plane helper functions to + * implement legacy plane updates (i.e., drm_plane->update_plane() and + * drm_plane->disable_plane()). This allows plane updates to use the + * atomic state infrastructure and perform plane updates as separate + * prepare/check/commit/cleanup steps. + */ + +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_plane_helper.h> +#include "intel_drv.h" + +/** + * intel_plane_duplicate_state - duplicate plane state + * @plane: drm plane + * + * Allocates and returns a copy of the plane state (both common and + * Intel-specific) for the specified plane. + * + * Returns: The newly allocated plane state, or NULL or failure. + */ +struct drm_plane_state * +intel_plane_duplicate_state(struct drm_plane *plane) +{ + struct intel_plane_state *state; + + if (plane->state) + state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL); + else + state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state) + return NULL; + + if (state->base.fb) + drm_framebuffer_reference(state->base.fb); + + return &state->base; +} + +/** + * intel_plane_destroy_state - destroy plane state + * @plane: drm plane + * @state: state object to destroy + * + * Destroys the plane state (both common and Intel-specific) for the + * specified plane. + */ +void +intel_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + drm_atomic_helper_plane_destroy_state(plane, state); +} + +static int intel_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_crtc *crtc = state->crtc; + struct intel_crtc *intel_crtc; + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_plane_state *intel_state = to_intel_plane_state(state); + + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); + + /* + * The original src/dest coordinates are stored in state->base, but + * we want to keep another copy internal to our driver that we can + * clip/modify ourselves. + */ + intel_state->src.x1 = state->src_x; + intel_state->src.y1 = state->src_y; + intel_state->src.x2 = state->src_x + state->src_w; + intel_state->src.y2 = state->src_y + state->src_h; + intel_state->dst.x1 = state->crtc_x; + intel_state->dst.y1 = state->crtc_y; + intel_state->dst.x2 = state->crtc_x + state->crtc_w; + intel_state->dst.y2 = state->crtc_y + state->crtc_h; + + /* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */ + intel_state->clip.x1 = 0; + intel_state->clip.y1 = 0; + intel_state->clip.x2 = + intel_crtc->active ? intel_crtc->config.pipe_src_w : 0; + intel_state->clip.y2 = + intel_crtc->active ? intel_crtc->config.pipe_src_h : 0; + + /* + * Disabling a plane is always okay; we just need to update + * fb tracking in a special way since cleanup_fb() won't + * get called by the plane helpers. + */ + if (state->fb == NULL && plane->state->fb != NULL) { + /* + * 'prepare' is never called when plane is being disabled, so + * we need to handle frontbuffer tracking as a special case + */ + intel_crtc->atomic.disabled_planes |= + (1 << drm_plane_index(plane)); + } + + return intel_plane->check_plane(plane, intel_state); +} + +static void intel_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_plane_state *intel_state = + to_intel_plane_state(plane->state); + + /* Don't disable an already disabled plane */ + if (!plane->state->fb && !old_state->fb) + return; + + intel_plane->commit_plane(plane, intel_state); +} + +const struct drm_plane_helper_funcs intel_plane_helper_funcs = { + .prepare_fb = intel_prepare_plane_fb, + .cleanup_fb = intel_cleanup_plane_fb, + .atomic_check = intel_plane_atomic_check, + .atomic_update = intel_plane_atomic_update, +}; + diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 2c7ed5cb29c0..ee41b882e71a 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -22,6 +22,9 @@ */ #include <linux/kernel.h> +#include <linux/component.h> +#include <drm/i915_component.h> +#include "intel_drv.h" #include <drm/drmP.h> #include <drm/drm_edid.h> @@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev) dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; } } + +static void i915_audio_component_get_power(struct device *dev) +{ + intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +static void i915_audio_component_put_power(struct device *dev) +{ + intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +/* Get CDCLK in kHz */ +static int i915_audio_component_get_cdclk_freq(struct device *dev) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + int ret; + + if (WARN_ON_ONCE(!HAS_DDI(dev_priv))) + return -ENODEV; + + intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); + ret = intel_ddi_get_cdclk_freq(dev_priv); + intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); + + return ret; +} + +static const struct i915_audio_component_ops i915_audio_component_ops = { + .owner = THIS_MODULE, + .get_power = i915_audio_component_get_power, + .put_power = i915_audio_component_put_power, + .get_cdclk_freq = i915_audio_component_get_cdclk_freq, +}; + +static int i915_audio_component_bind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + if (WARN_ON(acomp->ops || acomp->dev)) + return -EEXIST; + + acomp->ops = &i915_audio_component_ops; + acomp->dev = i915_dev; + + return 0; +} + +static void i915_audio_component_unbind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; +} + +static const struct component_ops i915_audio_component_bind_ops = { + .bind = i915_audio_component_bind, + .unbind = i915_audio_component_unbind, +}; + +/** + * i915_audio_component_init - initialize and register the audio component + * @dev_priv: i915 device instance + * + * This will register with the component framework a child component which + * will bind dynamically to the snd_hda_intel driver's corresponding master + * component when the latter is registered. During binding the child + * initializes an instance of struct i915_audio_component which it receives + * from the master. The master can then start to use the interface defined by + * this struct. Each side can break the binding at any point by deregistering + * its own component after which each side's component unbind callback is + * called. + * + * We ignore any error during registration and continue with reduced + * functionality (i.e. without HDMI audio). + */ +void i915_audio_component_init(struct drm_i915_private *dev_priv) +{ + int ret; + + ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops); + if (ret < 0) { + DRM_ERROR("failed to add audio component (%d)\n", ret); + /* continue with reduced functionality */ + return; + } + + dev_priv->audio_component_registered = true; +} + +/** + * i915_audio_component_cleanup - deregister the audio component + * @dev_priv: i915 device instance + * + * Deregisters the audio component, breaking any existing binding to the + * corresponding snd_hda_intel driver's master component. + */ +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) +{ + if (!dev_priv->audio_component_registered) + return; + + component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops); + dev_priv->audio_component_registered = false; +} diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 65b1fbc5eb57..3f178258d9f9 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -314,7 +314,6 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { const struct bdb_lfp_backlight_data *backlight_data; const struct bdb_lfp_backlight_data_entry *entry; - const struct bdb_lfp_backlight_control_data *bl_ctrl_data; backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); if (!backlight_data) @@ -327,7 +326,6 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) } entry = &backlight_data->data[panel_type]; - bl_ctrl_data = &backlight_data->blc_ctl[panel_type]; dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; if (!dev_priv->vbt.backlight.present) { @@ -339,30 +337,12 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; dev_priv->vbt.backlight.min_brightness = entry->min_brightness; - - dev_priv->vbt.backlight.controller = 0; - if (bdb->version >= 191) { - dev_priv->vbt.backlight.present = - bl_ctrl_data->pin == BLC_CONTROL_PIN_DDI; - if (!dev_priv->vbt.backlight.present) { - DRM_DEBUG_KMS("BL control pin is not DDI (pin %u)\n", - bl_ctrl_data->pin); - return; - } - if (bl_ctrl_data->controller == 1) - dev_priv->vbt.backlight.controller = - bl_ctrl_data->controller; - } - DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " "active %s, min brightness %u, level %u\n", dev_priv->vbt.backlight.pwm_freq_hz, dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", dev_priv->vbt.backlight.min_brightness, backlight_data->level[panel_type]); - - DRM_DEBUG_KMS("VBT BL controller %u\n", - dev_priv->vbt.backlight.controller); } /* Try to find sdvo panel data */ diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 9a7202e5caf4..a6a8710f665f 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -402,21 +402,10 @@ struct bdb_lfp_backlight_data_entry { u8 obsolete3; } __packed; -#define BLC_CONTROL_PIN_PMIC 0 -#define BLC_CONTROL_PIN_LPSS_PWM 1 -#define BLC_CONTROL_PIN_DDI 2 -#define BLC_CONTROL_PIN_CABC 3 - -struct bdb_lfp_backlight_control_data { - u8 controller:4; - u8 pin:4; -} __packed; - struct bdb_lfp_backlight_data { u8 entry_size; struct bdb_lfp_backlight_data_entry data[16]; u8 level[16]; - struct bdb_lfp_backlight_control_data blc_ctl[16]; } __packed; struct aimdb_header { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dc266e772340..91d8ada8fe6d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -98,6 +98,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_config *pipe_config); static void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_config *pipe_config); +static void intel_begin_crtc_commit(struct drm_crtc *crtc); +static void intel_finish_crtc_commit(struct drm_crtc *crtc); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -2165,7 +2167,8 @@ static void intel_disable_primary_hw_plane(struct drm_plane *plane, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - assert_pipe_enabled(dev_priv, intel_crtc->pipe); + if (WARN_ON(!intel_crtc->active)) + return; if (!intel_crtc->primary_enabled) return; @@ -4036,7 +4039,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc) } } -static void intel_enable_planes(struct drm_crtc *crtc) +static void intel_enable_sprite_planes(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; enum pipe pipe = to_intel_crtc(crtc)->pipe; @@ -4050,7 +4053,7 @@ static void intel_enable_planes(struct drm_crtc *crtc) } } -static void intel_disable_planes(struct drm_crtc *crtc) +static void intel_disable_sprite_planes(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; enum pipe pipe = to_intel_crtc(crtc)->pipe; @@ -4194,7 +4197,7 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; intel_enable_primary_hw_plane(crtc->primary, crtc); - intel_enable_planes(crtc); + intel_enable_sprite_planes(crtc); intel_crtc_update_cursor(crtc, true); intel_crtc_dpms_overlay(intel_crtc, true); @@ -4229,7 +4232,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); - intel_disable_planes(crtc); + intel_disable_sprite_planes(crtc); intel_disable_primary_hw_plane(crtc->primary, crtc); /* @@ -4301,15 +4304,15 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (intel_crtc->config.has_pch_encoder) ironlake_pch_enable(crtc); + assert_vblank_disabled(crtc); + drm_crtc_vblank_on(crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); if (HAS_PCH_CPT(dev)) cpt_verify_modeset(dev, intel_crtc->pipe); - assert_vblank_disabled(crtc); - drm_crtc_vblank_on(crtc); - intel_crtc_enable_planes(crtc); } @@ -4421,14 +4424,14 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) if (intel_crtc->config.dp_encoder_is_mst) intel_ddi_set_vc_payload_alloc(crtc, true); + assert_vblank_disabled(crtc); + drm_crtc_vblank_on(crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) { encoder->enable(encoder); intel_opregion_notify_encoder(encoder, true); } - assert_vblank_disabled(crtc); - drm_crtc_vblank_on(crtc); - /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ haswell_mode_set_planes_workaround(intel_crtc); @@ -4479,12 +4482,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc_disable_planes(crtc); - drm_crtc_vblank_off(crtc); - assert_vblank_disabled(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); + drm_crtc_vblank_off(crtc); + assert_vblank_disabled(crtc); + if (intel_crtc->config.has_pch_encoder) intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); @@ -4543,14 +4546,14 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_crtc_disable_planes(crtc); - drm_crtc_vblank_off(crtc); - assert_vblank_disabled(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); encoder->disable(encoder); } + drm_crtc_vblank_off(crtc); + assert_vblank_disabled(crtc); + if (intel_crtc->config.has_pch_encoder) intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, false); @@ -5018,12 +5021,12 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) - encoder->enable(encoder); - assert_vblank_disabled(crtc); drm_crtc_vblank_on(crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); + intel_crtc_enable_planes(crtc); /* Underruns don't raise interrupts, so check manually. */ @@ -5079,12 +5082,12 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) - encoder->enable(encoder); - assert_vblank_disabled(crtc); drm_crtc_vblank_on(crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); + intel_crtc_enable_planes(crtc); /* @@ -5156,12 +5159,12 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) */ intel_wait_for_vblank(dev, pipe); - drm_crtc_vblank_off(crtc); - assert_vblank_disabled(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); + drm_crtc_vblank_off(crtc); + assert_vblank_disabled(crtc); + intel_disable_pipe(intel_crtc); i9xx_pfit_disable(intel_crtc); @@ -9613,7 +9616,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_plane *primary = crtc->primary; - struct intel_plane *intel_plane = to_intel_plane(primary); enum pipe pipe = intel_crtc->pipe; struct intel_unpin_work *work; struct intel_engine_cs *ring; @@ -9772,15 +9774,7 @@ free_work: if (ret == -EIO) { out_hang: - ret = primary->funcs->update_plane(primary, crtc, fb, - intel_plane->crtc_x, - intel_plane->crtc_y, - intel_plane->crtc_h, - intel_plane->crtc_w, - intel_plane->src_x, - intel_plane->src_y, - intel_plane->src_h, - intel_plane->src_w); + ret = intel_plane_restore(primary); if (ret == 0 && event) { spin_lock_irq(&dev->event_lock); drm_send_vblank_event(dev, pipe, event); @@ -9793,6 +9787,8 @@ out_hang: static struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, + .atomic_begin = intel_begin_crtc_commit, + .atomic_flush = intel_finish_crtc_commit, }; /** @@ -11673,7 +11669,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, unsigned frontbuffer_bits = 0; int ret = 0; - if (WARN_ON(fb == plane->fb || !obj)) + if (!obj) return 0; switch (plane->type) { @@ -11737,13 +11733,20 @@ static int intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = state->base.crtc; + struct intel_crtc *intel_crtc; + struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; int ret; + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); + ret = drm_plane_helper_check_update(plane, crtc, fb, src, dest, clip, DRM_PLANE_HELPER_NO_SCALING, @@ -11752,10 +11755,40 @@ intel_check_primary_plane(struct drm_plane *plane, if (ret) return ret; - intel_crtc_wait_for_pending_flips(crtc); - if (intel_crtc_has_pending_flip(crtc)) { - DRM_ERROR("pipe is still busy with an old pageflip\n"); - return -EBUSY; + if (intel_crtc->active) { + intel_crtc->atomic.wait_for_flips = true; + + /* + * FBC does not work on some platforms for rotated + * planes, so disable it when rotation is not 0 and + * update it when rotation is set back to 0. + * + * FIXME: This is redundant with the fbc update done in + * the primary plane enable function except that that + * one is done too late. We eventually need to unify + * this. + */ + if (intel_crtc->primary_enabled && + INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + dev_priv->fbc.plane == intel_crtc->plane && + intel_plane->rotation != BIT(DRM_ROTATE_0)) { + intel_crtc->atomic.disable_fbc = true; + } + + if (state->visible) { + /* + * BDW signals flip done immediately if the plane + * is disabled, even if the plane enable is already + * armed to occur at the next vblank :( + */ + if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled) + intel_crtc->atomic.wait_vblank = true; + } + + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); + + intel_crtc->atomic.update_fbc = true; } return 0; @@ -11769,58 +11802,22 @@ intel_commit_primary_plane(struct drm_plane *plane, struct drm_framebuffer *fb = state->base.fb; struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_rect *src = &state->src; - enum pipe pipe = intel_plane->pipe; - if (!fb) { - /* - * 'prepare' is never called when plane is being disabled, so - * we need to handle frontbuffer tracking here - */ - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, - INTEL_FRONTBUFFER_PRIMARY(pipe)); - mutex_unlock(&dev->struct_mutex); - } + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); plane->fb = fb; crtc->x = src->x1 >> 16; crtc->y = src->y1 >> 16; - intel_plane->crtc_x = state->orig_dst.x1; - intel_plane->crtc_y = state->orig_dst.y1; - intel_plane->crtc_w = drm_rect_width(&state->orig_dst); - intel_plane->crtc_h = drm_rect_height(&state->orig_dst); - intel_plane->src_x = state->orig_src.x1; - intel_plane->src_y = state->orig_src.y1; - intel_plane->src_w = drm_rect_width(&state->orig_src); - intel_plane->src_h = drm_rect_height(&state->orig_src); intel_plane->obj = obj; if (intel_crtc->active) { - /* - * FBC does not work on some platforms for rotated - * planes, so disable it when rotation is not 0 and - * update it when rotation is set back to 0. - * - * FIXME: This is redundant with the fbc update done in - * the primary plane enable function except that that - * one is done too late. We eventually need to unify - * this. - */ - if (intel_crtc->primary_enabled && - INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && - dev_priv->fbc.plane == intel_crtc->plane && - intel_plane->rotation != BIT(DRM_ROTATE_0)) { - intel_fbc_disable(dev); - } - if (state->visible) { - bool was_enabled = intel_crtc->primary_enabled; - /* FIXME: kill this fastboot hack */ intel_update_pipe_size(intel_crtc); @@ -11828,14 +11825,6 @@ intel_commit_primary_plane(struct drm_plane *plane, dev_priv->display.update_primary_plane(crtc, plane->fb, crtc->x, crtc->y); - - /* - * BDW signals flip done immediately if the plane - * is disabled, even if the plane enable is already - * armed to occur at the next vblank :( - */ - if (IS_BROADWELL(dev) && !was_enabled) - intel_wait_for_vblank(dev, intel_crtc->pipe); } else { /* * If clipping results in a non-visible primary plane, @@ -11846,110 +11835,121 @@ intel_commit_primary_plane(struct drm_plane *plane, */ intel_disable_primary_hw_plane(plane, crtc); } - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); } } -int -intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +static void intel_begin_crtc_commit(struct drm_crtc *crtc) { - struct drm_device *dev = plane->dev; + struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *old_fb = plane->fb; - struct intel_plane_state state; - struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int ret; + struct intel_plane *intel_plane; + struct drm_plane *p; + unsigned fb_bits = 0; + + /* Track fb's for any planes being disabled */ + list_for_each_entry(p, &dev->mode_config.plane_list, head) { + intel_plane = to_intel_plane(p); + + if (intel_crtc->atomic.disabled_planes & + (1 << drm_plane_index(p))) { + switch (p->type) { + case DRM_PLANE_TYPE_PRIMARY: + fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe); + break; + case DRM_PLANE_TYPE_CURSOR: + fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe); + break; + } - state.base.crtc = crtc ? crtc : plane->crtc; - state.base.fb = fb; + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(intel_fb_obj(p->fb), NULL, fb_bits); + mutex_unlock(&dev->struct_mutex); + } + } - /* sample coordinates in 16.16 fixed point */ - state.src.x1 = src_x; - state.src.x2 = src_x + src_w; - state.src.y1 = src_y; - state.src.y2 = src_y + src_h; + if (intel_crtc->atomic.wait_for_flips) + intel_crtc_wait_for_pending_flips(crtc); - /* integer pixels */ - state.dst.x1 = crtc_x; - state.dst.x2 = crtc_x + crtc_w; - state.dst.y1 = crtc_y; - state.dst.y2 = crtc_y + crtc_h; + if (intel_crtc->atomic.disable_fbc) + intel_fbc_disable(dev); - state.clip.x1 = 0; - state.clip.y1 = 0; - state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0; - state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0; + if (intel_crtc->atomic.pre_disable_primary) + intel_pre_disable_primary(crtc); - state.orig_src = state.src; - state.orig_dst = state.dst; + if (intel_crtc->atomic.update_wm) + intel_update_watermarks(crtc); - ret = intel_plane->check_plane(plane, &state); - if (ret) - return ret; + intel_runtime_pm_get(dev_priv); - if (fb != old_fb && fb) { - ret = intel_prepare_plane_fb(plane, fb); - if (ret) - return ret; - } + /* Perform vblank evasion around commit operation */ + if (intel_crtc->active) + intel_crtc->atomic.evade = + intel_pipe_update_start(intel_crtc, + &intel_crtc->atomic.start_vbl_count); +} + +static void intel_finish_crtc_commit(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 drm_plane *p; + + if (intel_crtc->atomic.evade) + intel_pipe_update_end(intel_crtc, + intel_crtc->atomic.start_vbl_count); - intel_runtime_pm_get(dev_priv); - intel_plane->commit_plane(plane, &state); intel_runtime_pm_put(dev_priv); - if (fb != old_fb && old_fb) { - if (intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - intel_cleanup_plane_fb(plane, old_fb); + if (intel_crtc->atomic.wait_vblank) + intel_wait_for_vblank(dev, intel_crtc->pipe); + + intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits); + + if (intel_crtc->atomic.update_fbc) { + mutex_lock(&dev->struct_mutex); + intel_fbc_update(dev); + mutex_unlock(&dev->struct_mutex); } - plane->fb = fb; + if (intel_crtc->atomic.post_enable_primary) + intel_post_enable_primary(crtc); - return 0; + drm_for_each_legacy_plane(p, &dev->mode_config.plane_list) + if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p)) + intel_update_sprite_watermarks(p, crtc, 0, 0, 0, + false, false); + + memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic)); } /** - * intel_disable_plane - disable a plane - * @plane: plane to disable + * intel_plane_destroy - destroy a plane + * @plane: plane to destroy * - * General disable handler for all plane types. + * Common destruction function for all types of planes (primary, cursor, + * sprite). */ -int -intel_disable_plane(struct drm_plane *plane) -{ - if (!plane->fb) - return 0; - - if (WARN_ON(!plane->crtc)) - return -EINVAL; - - return plane->funcs->update_plane(plane, plane->crtc, NULL, - 0, 0, 0, 0, 0, 0, 0, 0); -} - -/* Common destruction function for both primary and cursor planes */ -static void intel_plane_destroy(struct drm_plane *plane) +void intel_plane_destroy(struct drm_plane *plane) { struct intel_plane *intel_plane = to_intel_plane(plane); + intel_plane_destroy_state(plane, plane->state); drm_plane_cleanup(plane); kfree(intel_plane); } static const struct drm_plane_funcs intel_primary_plane_funcs = { - .update_plane = intel_update_plane, - .disable_plane = intel_disable_plane, + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, .destroy = intel_plane_destroy, - .set_property = intel_plane_set_property + .set_property = intel_plane_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + }; static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, @@ -11963,6 +11963,12 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, if (primary == NULL) return NULL; + primary->base.state = intel_plane_duplicate_state(&primary->base); + if (primary->base.state == NULL) { + kfree(primary); + return NULL; + } + primary->can_scale = false; primary->max_downscale = 1; primary->pipe = pipe; @@ -11998,6 +12004,8 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->rotation); } + drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs); + return &primary->base; } @@ -12006,16 +12014,19 @@ intel_check_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_crtc *crtc = state->base.crtc; - struct drm_device *dev = crtc->dev; + struct drm_device *dev = plane->dev; struct drm_framebuffer *fb = state->base.fb; struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - int crtc_w, crtc_h; + struct intel_crtc *intel_crtc; unsigned stride; int ret; + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); + ret = drm_plane_helper_check_update(plane, crtc, fb, src, dest, clip, DRM_PLANE_HELPER_NO_SCALING, @@ -12027,18 +12038,17 @@ intel_check_cursor_plane(struct drm_plane *plane, /* if we want to turn off the cursor ignore width and height */ if (!obj) - return 0; + goto finish; /* Check for which cursor types we support */ - crtc_w = drm_rect_width(&state->orig_dst); - crtc_h = drm_rect_height(&state->orig_dst); - if (!cursor_size_ok(dev, crtc_w, crtc_h)) { - DRM_DEBUG("Cursor dimension not supported\n"); + if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) { + DRM_DEBUG("Cursor dimension %dx%d not supported\n", + state->base.crtc_w, state->base.crtc_h); return -EINVAL; } - stride = roundup_pow_of_two(crtc_w) * 4; - if (obj->base.size < stride * crtc_h) { + stride = roundup_pow_of_two(state->base.crtc_w) * 4; + if (obj->base.size < stride * state->base.crtc_h) { DRM_DEBUG_KMS("buffer is too small\n"); return -ENOMEM; } @@ -12054,6 +12064,15 @@ intel_check_cursor_plane(struct drm_plane *plane, } mutex_unlock(&dev->struct_mutex); +finish: + if (intel_crtc->active) { + if (intel_crtc->cursor_width != state->base.crtc_w) + intel_crtc->atomic.update_wm = true; + + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); + } + return ret; } @@ -12062,43 +12081,24 @@ intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_crtc *crtc = state->base.crtc; - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_device *dev = plane->dev; + struct intel_crtc *intel_crtc; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - enum pipe pipe = intel_crtc->pipe; - unsigned old_width; uint32_t addr; + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); + plane->fb = state->base.fb; - crtc->cursor_x = state->orig_dst.x1; - crtc->cursor_y = state->orig_dst.y1; - - intel_plane->crtc_x = state->orig_dst.x1; - intel_plane->crtc_y = state->orig_dst.y1; - intel_plane->crtc_w = drm_rect_width(&state->orig_dst); - intel_plane->crtc_h = drm_rect_height(&state->orig_dst); - intel_plane->src_x = state->orig_src.x1; - intel_plane->src_y = state->orig_src.y1; - intel_plane->src_w = drm_rect_width(&state->orig_src); - intel_plane->src_h = drm_rect_height(&state->orig_src); + crtc->cursor_x = state->base.crtc_x; + crtc->cursor_y = state->base.crtc_y; + intel_plane->obj = obj; if (intel_crtc->cursor_bo == obj) goto update; - /* - * 'prepare' is only called when fb != NULL; we still need to update - * frontbuffer tracking for the 'disable' case here. - */ - if (!obj) { - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(old_obj, NULL, - INTEL_FRONTBUFFER_CURSOR(pipe)); - mutex_unlock(&dev->struct_mutex); - } - if (!obj) addr = 0; else if (!INTEL_INFO(dev)->cursor_needs_physical) @@ -12109,25 +12109,20 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; update: - old_width = intel_crtc->cursor_width; + intel_crtc->cursor_width = state->base.crtc_w; + intel_crtc->cursor_height = state->base.crtc_h; - intel_crtc->cursor_width = drm_rect_width(&state->orig_dst); - intel_crtc->cursor_height = drm_rect_height(&state->orig_dst); - - if (intel_crtc->active) { - if (old_width != intel_crtc->cursor_width) - intel_update_watermarks(crtc); + if (intel_crtc->active) intel_crtc_update_cursor(crtc, state->visible); - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); - } } static const struct drm_plane_funcs intel_cursor_plane_funcs = { - .update_plane = intel_update_plane, - .disable_plane = intel_disable_plane, + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, .destroy = intel_plane_destroy, .set_property = intel_plane_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, }; static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, @@ -12139,6 +12134,12 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, if (cursor == NULL) return NULL; + cursor->base.state = intel_plane_duplicate_state(&cursor->base); + if (cursor->base.state == NULL) { + kfree(cursor); + return NULL; + } + cursor->can_scale = false; cursor->max_downscale = 1; cursor->pipe = pipe; @@ -12165,6 +12166,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, cursor->rotation); } + drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs); + return &cursor->base; } @@ -12390,14 +12393,16 @@ static void intel_setup_outputs(struct drm_device *dev) * eDP ports. Consult the VBT as well as DP_DETECTED to * detect eDP ports. */ - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED && + !intel_dp_is_edp(dev, PORT_B)) intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, PORT_B); if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED || intel_dp_is_edp(dev, PORT_B)) intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) + if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED && + !intel_dp_is_edp(dev, PORT_C)) intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, PORT_C); if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED || diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 88d81a8b0d35..df7b558f3222 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3773,7 +3773,7 @@ go_again: intel_dp_stop_link_train(intel_dp); } - DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]); + DRM_DEBUG_KMS("got esi %3ph\n", esi); ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled); if (handled) { @@ -3789,7 +3789,7 @@ go_again: bret = intel_dp_get_sink_irq_esi(intel_dp, esi); if (bret == true) { - DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]); + DRM_DEBUG_KMS("got esi2 %3ph\n", esi); goto go_again; } } else diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb871f3cfe2e..30e968f8c55e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -248,9 +248,13 @@ struct intel_plane_state { struct drm_rect src; struct drm_rect dst; struct drm_rect clip; - struct drm_rect orig_src; - struct drm_rect orig_dst; bool visible; + + /* + * used only for sprite planes to determine when to implicitly + * enable/disable the primary plane + */ + bool hides_primary; }; struct intel_plane_config { @@ -415,6 +419,32 @@ struct skl_pipe_wm { uint32_t linetime; }; +/* + * Tracking of operations that need to be performed at the beginning/end of an + * atomic commit, outside the atomic section where interrupts are disabled. + * These are generally operations that grab mutexes or might otherwise sleep + * and thus can't be run with interrupts disabled. + */ +struct intel_crtc_atomic_commit { + /* vblank evasion */ + bool evade; + unsigned start_vbl_count; + + /* Sleepable operations to perform before commit */ + bool wait_for_flips; + bool disable_fbc; + bool pre_disable_primary; + bool update_wm; + unsigned disabled_planes; + + /* Sleepable operations to perform after commit */ + unsigned fb_bits; + bool wait_vblank; + bool update_fbc; + bool post_enable_primary; + unsigned update_sprite_watermarks; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -468,6 +498,8 @@ struct intel_crtc { int scanline_offset; struct intel_mmio_flip mmio_flip; + + struct intel_crtc_atomic_commit atomic; }; struct intel_plane_wm_parameters { @@ -485,10 +517,6 @@ struct intel_plane { struct drm_i915_gem_object *obj; bool can_scale; int max_downscale; - int crtc_x, crtc_y; - unsigned int crtc_w, crtc_h; - uint32_t src_x, src_y; - uint32_t src_w, src_h; unsigned int rotation; /* Since we need to change the watermarks before/after @@ -542,6 +570,7 @@ struct cxsr_latency { #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) #define to_intel_plane(x) container_of(x, struct intel_plane, base) +#define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base) #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL) struct intel_hdmi { @@ -874,6 +903,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); void intel_init_audio(struct drm_device *dev); void intel_audio_codec_enable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder); +void i915_audio_component_init(struct drm_i915_private *dev_priv); +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); /* intel_display.c */ bool intel_has_pending_fb_unpin(struct drm_device *dev); @@ -1021,6 +1052,7 @@ int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); int intel_disable_plane(struct drm_plane *plane); +void intel_plane_destroy(struct drm_plane *plane); /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); @@ -1214,8 +1246,16 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count); void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count); +void intel_post_enable_primary(struct drm_crtc *crtc); +void intel_pre_disable_primary(struct drm_crtc *crtc); /* intel_tv.c */ void intel_tv_init(struct drm_device *dev); +/* intel_atomic.c */ +struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane); +void intel_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); +extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7670a0f0f620..e405b61cdac5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1137,6 +1137,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); POSTING_READ(RING_MODE_GEN7(ring)); + ring->next_context_status_buffer = 0; DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); @@ -1394,7 +1395,6 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin INIT_LIST_HEAD(&ring->execlist_queue); INIT_LIST_HEAD(&ring->execlist_retired_req_list); spin_lock_init(&ring->execlist_lock); - ring->next_context_status_buffer = 0; ret = i915_cmd_parser_init_ring(ring); if (ret) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7d99a9c4e49b..03fc7f2ee9d1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4681,8 +4681,7 @@ static void cherryview_enable_rps(struct drm_device *dev) I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); I915_WRITE(GEN6_RC_SLEEP, 0); - /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */ - I915_WRITE(GEN6_RC6_THRESHOLD, 0x557); + I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */ /* allows RC6 residency counter to work */ I915_WRITE(VLV_COUNTER_CONTROL, @@ -4696,7 +4695,7 @@ static void cherryview_enable_rps(struct drm_device *dev) /* 3: Enable RC6 */ if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) && (pcbr >> VLV_PCBR_ADDR_SHIFT)) - rc6_mode = GEN7_RC_CTL_TO_MODE; + rc6_mode = GEN6_RC_CTL_EI_MODE(1); I915_WRITE(GEN6_RC_CONTROL, rc6_mode); @@ -5974,6 +5973,10 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_GT_MODE, _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4)); + /* WaSampleCChickenBitEnable:hsw */ + I915_WRITE(HALF_SLICE_CHICKEN3, + _MASKED_BIT_ENABLE(HSW_SAMPLE_C_PERFORMANCE)); + /* WaSwitchSolVfFArbitrationPriority:hsw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index dd0e6e0447d4..5ae193ec464a 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -143,7 +143,6 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t aux_clock_divider; int precharge = 0x3; - bool only_standby = dev_priv->vbt.psr.full_link; static const uint8_t aux_msg[] = { [0] = DP_AUX_NATIVE_WRITE << 4, [1] = DP_SET_POWER >> 8, @@ -157,16 +156,13 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); - if (IS_BROADWELL(dev) && dig_port->port != PORT_A) - only_standby = true; - /* Enable PSR in sink */ - if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) + if (dev_priv->psr.link_standby) drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, - DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE); + DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); else drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, - DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); + DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE); /* Setup AUX registers */ for (i = 0; i < sizeof(aux_msg); i += 4) @@ -226,12 +222,8 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp) dev_priv->vbt.psr.idle_frames + 1 : 2; uint32_t val = 0x0; const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; - bool only_standby = false; - if (IS_BROADWELL(dev) && dig_port->port != PORT_A) - only_standby = true; - - if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) { + if (dev_priv->psr.link_standby) { val |= EDP_PSR_LINK_STANDBY; val |= EDP_PSR_TP2_TP3_TIME_0us; val |= EDP_PSR_TP1_TIME_0us; @@ -270,22 +262,19 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp) return false; } - /* Below limitations aren't valid for Broadwell */ - if (IS_BROADWELL(dev)) - goto out; - - if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) & - S3D_ENABLE) { + if (IS_HASWELL(dev) && + I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) & + S3D_ENABLE) { DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n"); return false; } - if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) { + if (IS_HASWELL(dev) && + intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) { DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n"); return false; } - out: dev_priv->psr.source_ok = true; return true; } @@ -344,6 +333,13 @@ void intel_psr_enable(struct intel_dp *intel_dp) if (!intel_psr_match_conditions(intel_dp)) goto unlock; + /* First we check VBT, but we must respect sink and source + * known restrictions */ + dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; + if ((intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) || + (IS_BROADWELL(dev) && intel_dig_port->port != PORT_A)) + dev_priv->psr.link_standby = true; + dev_priv->psr.busy_frontbuffer_bits = 0; if (HAS_DDI(dev)) { @@ -620,13 +616,11 @@ void intel_psr_flush(struct drm_device *dev, /* * On Valleyview and Cherryview we don't use hardware tracking so - * sprite plane updates or cursor moves don't result in a PSR + * any plane updates or cursor moves don't result in a PSR * invalidating. Which means we need to manually fake this in * software for all flushes, not just when we've seen a preceding * invalidation through frontbuffer rendering. */ - if (!HAS_DDI(dev) && - ((frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)) || - (frontbuffer_bits & INTEL_FRONTBUFFER_CURSOR(pipe)))) + if (!HAS_DDI(dev)) intel_psr_exit(dev); if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 12a36f0ca53d..23020d67329b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -796,6 +796,16 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) HDC_DONOT_FETCH_MEM_WHEN_MASKED | (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); + /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: + * "The Hierarchical Z RAW Stall Optimization allows non-overlapping + * polygons in the same 8x4 pixel/sample area to be processed without + * stalling waiting for the earlier ones to write to Hierarchical Z + * buffer." + * + * This optimization is off by default for Broadwell; turn it on. + */ + WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); + /* Wa4x4STCOptimizationDisable:bdw */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); @@ -836,6 +846,14 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) HDC_FORCE_NON_COHERENT | HDC_DONOT_FETCH_MEM_WHEN_MASKED); + /* According to the CACHE_MODE_0 default value documentation, some + * CHV platforms disable this optimization by default. Turn it on. + */ + WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); + + /* Improve HiZ throughput on CHV. */ + WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); + return 0; } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 39e1b071765d..8bf7bb4a12bc 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -31,7 +31,6 @@ #include "i915_drv.h" #include "intel_drv.h" -#include <drm/i915_powerwell.h> /** * DOC: runtime pm @@ -50,8 +49,6 @@ * present for a given platform. */ -static struct i915_power_domains *hsw_pwr; - #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ i < (power_domains)->power_well_count && \ @@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) */ if (IS_HASWELL(dev_priv->dev)) { set_power_wells(power_domains, hsw_power_wells); - hsw_pwr = power_domains; } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); - hsw_pwr = power_domains; } else if (IS_CHERRYVIEW(dev_priv->dev)) { set_power_wells(power_domains, chv_power_wells); } else if (IS_VALLEYVIEW(dev_priv->dev)) { @@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv) * the power well is not enabled, so just enable it in case * we're going to unload/reload. */ intel_display_set_init_power(dev_priv, true); - - hsw_pwr = NULL; } static void intel_power_domains_resume(struct drm_i915_private *dev_priv) @@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) pm_runtime_put_autosuspend(device); } -/* Display audio driver power well request */ -int i915_request_power_well(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); - return 0; -} -EXPORT_SYMBOL_GPL(i915_request_power_well); - -/* Display audio driver power well release */ -int i915_release_power_well(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); - return 0; -} -EXPORT_SYMBOL_GPL(i915_release_power_well); - -/* - * Private interface for the audio driver to get CDCLK in kHz. - * - * Caller must request power well using i915_request_power_well() prior to - * making the call. - */ -int i915_get_cdclk_freq(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - - return intel_ddi_get_cdclk_freq(dev_priv); -} -EXPORT_SYMBOL_GPL(i915_get_cdclk_freq); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 6d7a277458b5..4e3d362931e9 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1617,6 +1617,9 @@ static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo) struct drm_device *dev = intel_sdvo->base.base.dev; uint16_t hotplug; + if (!I915_HAS_HOTPLUG(dev)) + return 0; + /* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise * on the line. */ if (IS_I945G(dev) || IS_I945GM(dev)) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index c18e57d36c2c..dca3f70ef1ba 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -33,6 +33,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_fourcc.h> #include <drm/drm_rect.h> +#include <drm/drm_plane_helper.h> #include "intel_drv.h" #include <drm/i915_drm.h> #include "i915_drv.h" @@ -412,8 +413,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, u32 sprctl; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - u32 start_vbl_count; - bool atomic_update; sprctl = I915_READ(SPCNTR(pipe, plane)); @@ -502,8 +501,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - intel_update_primary_plane(intel_crtc); if (IS_CHERRYVIEW(dev) && pipe == PIPE_B) @@ -525,9 +522,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, sprsurf_offset); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -539,10 +533,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; int plane = intel_plane->plane; - u32 start_vbl_count; - bool atomic_update; - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -553,9 +543,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) intel_flush_primary_plane(dev_priv, intel_crtc->plane); - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); - intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } @@ -626,8 +613,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - u32 start_vbl_count; - bool atomic_update; sprctl = I915_READ(SPRCTL(pipe)); @@ -711,8 +696,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } } - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - intel_update_primary_plane(intel_crtc); I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); @@ -735,9 +718,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -748,10 +728,6 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; - u32 start_vbl_count; - bool atomic_update; - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -764,16 +740,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) intel_flush_primary_plane(dev_priv, intel_crtc->plane); - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); - /* * Avoid underruns when disabling the sprite. * FIXME remove once watermark updates are done properly. */ - intel_wait_for_vblank(dev, pipe); - - intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false); + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane)); } static int @@ -846,8 +818,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - u32 start_vbl_count; - bool atomic_update; dvscntr = I915_READ(DVSCNTR(pipe)); @@ -922,8 +892,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); - intel_update_primary_plane(intel_crtc); I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); @@ -941,9 +909,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); intel_flush_primary_plane(dev_priv, intel_crtc->plane); - - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); } static void @@ -954,10 +919,6 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; - u32 start_vbl_count; - bool atomic_update; - - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -969,19 +930,25 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) intel_flush_primary_plane(dev_priv, intel_crtc->plane); - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); - /* * Avoid underruns when disabling the sprite. * FIXME remove once watermark updates are done properly. */ - intel_wait_for_vblank(dev, pipe); - - intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false); + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane)); } -static void +/** + * intel_post_enable_primary - Perform operations after enabling primary plane + * @crtc: the CRTC whose primary plane was just enabled + * + * Performs potentially sleeping operations that must be done after the primary + * plane is enabled, such as updating FBC and IPS. Note that this may be + * called due to an explicit primary plane update, or due to an implicit + * re-enable that is caused when a sprite plane is updated to no longer + * completely hide the primary plane. + */ +void intel_post_enable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -1008,7 +975,17 @@ intel_post_enable_primary(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -static void +/** + * intel_pre_disable_primary - Perform operations before disabling primary plane + * @crtc: the CRTC whose primary plane is to be disabled + * + * Performs potentially sleeping operations that must be done before the + * primary plane is enabled, such as updating FBC and IPS. Note that this may + * be called due to an explicit primary plane update, or due to an implicit + * disable that is caused when a sprite plane completely hides the primary + * plane. + */ +void intel_pre_disable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -1105,15 +1082,16 @@ intel_check_sprite_plane(struct drm_plane *plane, uint32_t src_x, src_y, src_w, src_h; struct drm_rect *src = &state->src; struct drm_rect *dst = &state->dst; - struct drm_rect *orig_src = &state->orig_src; const struct drm_rect *clip = &state->clip; int hscale, vscale; int max_scale, min_scale; int pixel_size; + intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); + if (!fb) { state->visible = false; - return 0; + goto finish; } /* Don't modify another pipe's plane */ @@ -1191,10 +1169,10 @@ intel_check_sprite_plane(struct drm_plane *plane, intel_plane->rotation); /* sanity check to make sure the src viewport wasn't enlarged */ - WARN_ON(src->x1 < (int) orig_src->x1 || - src->y1 < (int) orig_src->y1 || - src->x2 > (int) orig_src->x2 || - src->y2 > (int) orig_src->y2); + WARN_ON(src->x1 < (int) state->base.src_x || + src->y1 < (int) state->base.src_y || + src->x2 > (int) state->base.src_x + state->base.src_w || + src->y2 > (int) state->base.src_y + state->base.src_h); /* * Hardware doesn't handle subpixel coordinates. @@ -1260,6 +1238,29 @@ intel_check_sprite_plane(struct drm_plane *plane, dst->y1 = crtc_y; dst->y2 = crtc_y + crtc_h; +finish: + /* + * If the sprite is completely covering the primary plane, + * we can disable the primary and save power. + */ + state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) && + !colorkey_enabled(intel_plane); + WARN_ON(state->hides_primary && !state->visible && intel_crtc->active); + + if (intel_crtc->active) { + if (intel_crtc->primary_enabled == state->hides_primary) + intel_crtc->atomic.wait_for_flips = true; + + if (intel_crtc->primary_enabled && state->hides_primary) + intel_crtc->atomic.pre_disable_primary = true; + + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); + + if (!intel_crtc->primary_enabled && !state->hides_primary) + intel_crtc->atomic.post_enable_primary = true; + } + return 0; } @@ -1267,58 +1268,23 @@ static void intel_commit_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { - struct drm_device *dev = plane->dev; struct drm_crtc *crtc = state->base.crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc; struct intel_plane *intel_plane = to_intel_plane(plane); - enum pipe pipe = intel_crtc->pipe; struct drm_framebuffer *fb = state->base.fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); int crtc_x, crtc_y; unsigned int crtc_w, crtc_h; uint32_t src_x, src_y, src_w, src_h; - struct drm_rect *dst = &state->dst; - const struct drm_rect *clip = &state->clip; - bool primary_enabled; - /* - * 'prepare' is never called when plane is being disabled, so we need - * to handle frontbuffer tracking here - */ - if (!fb) { - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, - INTEL_FRONTBUFFER_SPRITE(pipe)); - mutex_unlock(&dev->struct_mutex); - } + crtc = crtc ? crtc : plane->crtc; + intel_crtc = to_intel_crtc(crtc); - /* - * If the sprite is completely covering the primary plane, - * we can disable the primary and save power. - */ - primary_enabled = !drm_rect_equals(dst, clip) || colorkey_enabled(intel_plane); - WARN_ON(!primary_enabled && !state->visible && intel_crtc->active); - - intel_plane->crtc_x = state->orig_dst.x1; - intel_plane->crtc_y = state->orig_dst.y1; - intel_plane->crtc_w = drm_rect_width(&state->orig_dst); - intel_plane->crtc_h = drm_rect_height(&state->orig_dst); - intel_plane->src_x = state->orig_src.x1; - intel_plane->src_y = state->orig_src.y1; - intel_plane->src_w = drm_rect_width(&state->orig_src); - intel_plane->src_h = drm_rect_height(&state->orig_src); + plane->fb = state->base.fb; intel_plane->obj = obj; if (intel_crtc->active) { - bool primary_was_enabled = intel_crtc->primary_enabled; - - intel_crtc->primary_enabled = primary_enabled; - - if (primary_was_enabled != primary_enabled) - intel_crtc_wait_for_pending_flips(crtc); - - if (primary_was_enabled && !primary_enabled) - intel_pre_disable_primary(crtc); + intel_crtc->primary_enabled = !state->hides_primary; if (state->visible) { crtc_x = state->dst.x1; @@ -1335,23 +1301,9 @@ intel_commit_sprite_plane(struct drm_plane *plane, } else { intel_plane->disable_plane(plane, crtc); } - - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_SPRITE(pipe)); - - if (!primary_was_enabled && primary_enabled) - intel_post_enable_primary(crtc); } } -static void intel_destroy_plane(struct drm_plane *plane) -{ - struct intel_plane *intel_plane = to_intel_plane(plane); - intel_disable_plane(plane); - drm_plane_cleanup(plane); - kfree(intel_plane); -} - int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1439,23 +1391,23 @@ int intel_plane_set_property(struct drm_plane *plane, int intel_plane_restore(struct drm_plane *plane) { - struct intel_plane *intel_plane = to_intel_plane(plane); - if (!plane->crtc || !plane->fb) return 0; return plane->funcs->update_plane(plane, plane->crtc, plane->fb, - intel_plane->crtc_x, intel_plane->crtc_y, - intel_plane->crtc_w, intel_plane->crtc_h, - intel_plane->src_x, intel_plane->src_y, - intel_plane->src_w, intel_plane->src_h); + plane->state->crtc_x, plane->state->crtc_y, + plane->state->crtc_w, plane->state->crtc_h, + plane->state->src_x, plane->state->src_y, + plane->state->src_w, plane->state->src_h); } -static const struct drm_plane_funcs intel_plane_funcs = { - .update_plane = intel_update_plane, - .disable_plane = intel_disable_plane, - .destroy = intel_destroy_plane, +static const struct drm_plane_funcs intel_sprite_plane_funcs = { + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, + .destroy = intel_plane_destroy, .set_property = intel_plane_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, }; static uint32_t ilk_plane_formats[] = { @@ -1517,6 +1469,13 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) if (!intel_plane) return -ENOMEM; + intel_plane->base.state = + intel_plane_duplicate_state(&intel_plane->base); + if (intel_plane->base.state == NULL) { + kfree(intel_plane); + return -ENOMEM; + } + switch (INTEL_INFO(dev)->gen) { case 5: case 6: @@ -1591,7 +1550,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->commit_plane = intel_commit_sprite_plane; possible_crtcs = (1 << pipe); ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, - &intel_plane_funcs, + &intel_sprite_plane_funcs, plane_formats, num_plane_formats, DRM_PLANE_TYPE_OVERLAY); if (ret) { @@ -1610,6 +1569,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) dev->mode_config.rotation_property, intel_plane->rotation); + drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); + out: return ret; } |